1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2025-01-19 04:52:12 +01:00

Merged in mindnever/librepilot/LP-512_Support_F3_boards (pull request #426)

LP-512 Support F3 boards

Approved-by: Lalanne Laurent <f5soh@free.fr>
Approved-by: Mateusz Kaduk <mateusz.kaduk@gmail.com>
Approved-by: Vladimir Zidar <mr_w@mindnever.org>
Approved-by: Philippe Renon <philippe_renon@yahoo.fr>
This commit is contained in:
Vladimir Zidar 2017-06-04 11:31:35 +00:00 committed by Lalanne Laurent
commit 0177a824d3
275 changed files with 29245 additions and 4101 deletions

View File

@ -340,6 +340,7 @@ PACKAGE_FW_TARGETS += fw_oplinkmini
PACKAGE_FW_TARGETS += fw_gpsplatinum
PACKAGE_FW_TARGETS += fw_osd
PACKAGE_FW_TARGETS += fw_revoproto
PACKAGE_FW_TARGETS += fw_spracingf3evo fw_spracingf3 fw_nucleof303re fw_pikoblx fw_tinyfish
# Rules to generate GCS resources used to embed firmware binaries into the GCS.
# They are used later by the vehicle setup wizard to update board firmware.

View File

@ -14,12 +14,16 @@ ALL_BOARDS += oplinkmini
ALL_BOARDS += gpsplatinum
ALL_BOARDS += osd
ALL_BOARDS += discoveryf4bare
ALL_BOARDS += ccf3d spracingf3 spracingf3evo nucleof303re pikoblx tinyfish
# SimPosix only builds on Linux
ifeq ($(UNAME), Linux)
ALL_BOARDS += simposix
endif
# Short names of each board (used to display board name in parallel builds)
spracingf3_short := 'srf3'
spracingf3evo_short := 'spev'
ccf3d_short := 'cf3d'
coptercontrol_short := 'cc '
oplinkmini_short := 'oplm'
revolution_short := 'revo'
@ -30,6 +34,9 @@ sparky2_short := 'spk2'
simposix_short := 'posx'
discoveryf4bare_short := 'df4b'
gpsplatinum_short := 'gps9'
nucleof303re_short := 'nf3r'
pikoblx_short := 'piko'
tinyfish_short := 'tfsh'
# Start out assuming that we'll build fw, bl and bu for all boards
FW_BOARDS := $(ALL_BOARDS)

View File

@ -8,6 +8,7 @@
/* Begin PBXFileReference section */
4354B66314FED9FE004BA3B4 /* flight */ = {isa = PBXFileReference; lastKnownFileType = folder; name = flight; path = ../..; sourceTree = SOURCE_ROOT; };
5985F6EF1ED7911600B90A89 /* ground */ = {isa = PBXFileReference; lastKnownFileType = folder; name = ground; path = ../../../ground; sourceTree = "<group>"; };
65173C9F12EBFD1700D6A7CB /* Makefile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.make; name = Makefile; path = ../../../Makefile; sourceTree = SOURCE_ROOT; };
65904F1814632C1700FD9482 /* firmware-defs.mk */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "firmware-defs.mk"; sourceTree = "<group>"; };
65904F2214632C1700FD9482 /* board-info.mk */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "board-info.mk"; sourceTree = "<group>"; };
@ -34,6 +35,7 @@
isa = PBXGroup;
children = (
4354B66314FED9FE004BA3B4 /* flight */,
5985F6EF1ED7911600B90A89 /* ground */,
65904F1614632C1700FD9482 /* make */,
65C35E4E12EFB2F3004811C2 /* shared */,
65173C9F12EBFD1700D6A7CB /* Makefile */,

View File

@ -7,12 +7,18 @@
#include <stdint.h>
#include "inc/dcc_stdio.h"
#ifdef STM32F4XX
#ifdef STM32F4
# include <stm32f4xx.h>
#endif
#ifdef STM32F3
# include <stm32f30x.h>
#endif
#ifdef STM32F2XX
# include <stm32f2xx.h>
#endif
#ifdef STM32F1
# include <stm32f10x.h>
#endif
#define FAULT_TRAMPOLINE(_vec) \
__attribute__((naked, no_instrument_function)) \

View File

@ -2,6 +2,7 @@
******************************************************************************
*
* @file op_dfu.h
* @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017.
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @brief
* @see The GNU Public License (GPL) Version 3
@ -26,9 +27,91 @@
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __OP_DFU_H
#define __OP_DFU_H
#include "common.h"
/* Includes ------------------------------------------------------------------*/
/* Exported types ------------------------------------------------------------*/
typedef enum {
start, keepgoing,
} DownloadAction;
/**************************************************/
/* OP_DFU states */
/**************************************************/
typedef enum {
DFUidle, // 0
uploading, // 1
wrong_packet_received, // 2
too_many_packets, // 3
too_few_packets, // 4
Last_operation_Success, // 5
downloading, // 6
BLidle, // 7
Last_operation_failed, // 8
uploadingStarting, // 9
outsideDevCapabilities, // 10
CRC_Fail, // 11
failed_jump,
// 12
} DFUStates;
/**************************************************/
/* OP_DFU commands */
/**************************************************/
typedef enum {
Reserved, // 0
Req_Capabilities, // 1
Rep_Capabilities, // 2
EnterDFU, // 3
JumpFW, // 4
Reset, // 5
Abort_Operation, // 6
Upload, // 7
Op_END, // 8
Download_Req, // 9
Download, // 10
Status_Request, // 11
Status_Rep
// 12
} DFUCommands;
typedef enum {
High_Density, Medium_Density
} DeviceType;
/**************************************************/
/* OP_DFU transfer types */
/**************************************************/
typedef enum {
FW, // 0
Descript
// 2
} DFUTransfer;
/**************************************************/
/* OP_DFU transfer port */
/**************************************************/
typedef enum {
Usb, // 0
Serial
// 2
} DFUPort;
/**************************************************/
/* OP_DFU programable programable HW types */
/**************************************************/
typedef enum {
Self_flash, // 0
Remote_flash_via_spi
// 1
} DFUProgType;
/**************************************************/
/* OP_DFU programable sources */
/**************************************************/
#define USB 0
#define SPI 1
#define DownloadDelay 100000
#define MAX_DEL_RETRYS 3
#define MAX_WRI_RETRYS 3
typedef struct {
uint8_t programmingType;
uint8_t readWriteFlags;

View File

@ -42,6 +42,18 @@
#define ALARM_LED_OFF()
#endif
#ifdef PIOS_BUZZER_ALARM
#define ALARM_BUZZER_ON() \
{ if (buzzer_enabled) { PIOS_LED_On(PIOS_BUZZER_ALARM); } \
}
#define ALARM_BUZZER_OFF() \
{ if (buzzer_enabled) { PIOS_LED_Off(PIOS_BUZZER_ALARM); } \
}
#else
#define ALARM_BUZZER_ON()
#define ALARM_BUZZER_OFF()
#endif
#ifdef PIOS_LED_HEARTBEAT
#define HEARTBEAT_LED_ON() PIOS_LED_On(PIOS_LED_HEARTBEAT)
#define HEARTBEAT_LED_OFF() PIOS_LED_Off(PIOS_LED_HEARTBEAT)
@ -135,9 +147,10 @@ static volatile FlightStatusData currentFlightStatus;
static volatile bool started = false;
static volatile pios_notify_notification nextNotification = NOTIFY_NONE;
#ifdef PIOS_LED_ALARM
#if defined(PIOS_LED_ALARM) || defined(PIOS_BUZZER_ALARM)
static bool handleAlarms(uint16_t *r_pattern, uint16_t *b_pattern);
#endif // PIOS_LED_ALARM
#endif // PIOS_LED_ALARM || PIOS_BUZZER_ALARM
static bool handleNotifications(pios_notify_notification runningNotification, uint16_t *r_pattern, uint16_t *b_pattern);
static void handleFlightMode(uint16_t *r_pattern, uint16_t *b_pattern);
static void handleHeartbeat(uint16_t *r_pattern, uint16_t *b_pattern);
@ -163,6 +176,10 @@ void NotificationOnboardLedsRun()
static uint8_t lastFlightMode = -1;
static bool forceShowFlightMode = false;
static pios_notify_notification runningNotification = NOTIFY_NONE;
#ifdef PIOS_BUZZER_ALARM
static bool buzzer_enabled = false;
#endif
static enum {
STATUS_NOTIFY,
STATUS_ALARM,
@ -206,6 +223,7 @@ void NotificationOnboardLedsRun()
if (cycleCount & 0x10) {
HEARTBEAT_LED_OFF();
ALARM_LED_OFF();
ALARM_BUZZER_OFF();
cycleCount = 0x0;
forceShowFlightMode = false;
// Notification has been just shown, cleanup
@ -213,6 +231,9 @@ void NotificationOnboardLedsRun()
runningNotification = NOTIFY_NONE;
}
status = (status + 1) % STATUS_LENGHT;
#ifdef PIOS_BUZZER_ALARM
buzzer_enabled = true; /* This is the place where we update buzzer_enabled status based on (not yet implemented) NotificationSettings.Buzzer config */
#endif
}
if (status == STATUS_NOTIFY) {
@ -224,7 +245,7 @@ void NotificationOnboardLedsRun()
// Handles Alarm display
if (status == STATUS_ALARM) {
#ifdef PIOS_LED_ALARM
#if defined(PIOS_LED_ALARM) || defined(PIOS_BUZZER_ALARM)
if (!cycleCount && !handleAlarms(&r_pattern, &b_pattern)) {
// no alarms, advance
status++;
@ -252,14 +273,16 @@ void NotificationOnboardLedsRun()
}
if (r_pattern & 0x1) {
ALARM_LED_ON();
ALARM_BUZZER_ON();
} else {
ALARM_LED_OFF();
ALARM_BUZZER_OFF();
}
r_pattern >>= 1;
b_pattern >>= 1;
}
#if defined(PIOS_LED_ALARM)
#if defined(PIOS_LED_ALARM) || defined(PIOS_BUZZER_ALARM)
static bool handleAlarms(uint16_t *r_pattern, uint16_t *b_pattern)
{
if (currentAlarmLevel == SYSTEMALARMS_ALARM_OK) {
@ -269,7 +292,7 @@ static bool handleAlarms(uint16_t *r_pattern, uint16_t *b_pattern)
*r_pattern = BLINK_R_ALARM_PATTERN(currentAlarmLevel);
return true;
}
#endif /* PIOS_LED_ALARM */
#endif /* PIOS_LED_ALARM || PIOS_BUZZER_ALARM */
static bool handleNotifications(pios_notify_notification runningNotification, uint16_t *r_pattern, uint16_t *b_pattern)

View File

@ -157,7 +157,8 @@ void processComand(uint8_t *xReceive_Buffer)
switch (Command) {
case EnterDFU:
if (((DeviceState == BLidle) && (Data0 < numberOfDevices))
|| (DeviceState == DFUidle)) {
|| (DeviceState == DFUidle)
|| (DeviceState == failed_jump)) {
if (Data0 > 0) {
OPDfuIni(true);
}

View File

@ -54,14 +54,16 @@ include $(FREERTOS_DIR)/library.mk
OPTESTS = $(TOPDIR)/Tests
## PIOS Hardware
ifeq ($(MCU),cortex-m3)
ifneq (,$(findstring STM32F10,$(CHIP)))
include $(PIOS)/stm32f10x/library.mk
else ifeq ($(MCU),cortex-m4)
else ifneq (,$(findstring STM32F4,$(CHIP)))
include $(PIOS)/stm32f4xx/library.mk
else ifeq ($(MCU),cortex-m0)
else ifneq (,$(findstring STM32F30,$(CHIP)))
include $(PIOS)/stm32f30x/library.mk
else ifneq (,$(findstring STM32F0,$(CHIP)))
include $(PIOS)/stm32f0x/library.mk
else
$(error Unsupported MCU: $(MCU))
$(error Unsupported CHIP: $(CHIP))
endif
# List C source files here (C dependencies are automatically generated).
@ -83,6 +85,7 @@ SRC += $(PIOSCOMMON)/pios_mpu9250.c
SRC += $(PIOSCOMMON)/pios_mpxv.c
SRC += $(PIOSCOMMON)/pios_ms4525do.c
SRC += $(PIOSCOMMON)/pios_ms5611.c
SRC += $(PIOSCOMMON)/pios_bmp280.c
SRC += $(PIOSCOMMON)/pios_oplinkrcvr.c
SRC += $(PIOSCOMMON)/pios_video.c
SRC += $(PIOSCOMMON)/pios_wavplay.c
@ -150,6 +153,11 @@ ifeq ($(USE_CXX),YES)
CPPSRC += $(FLIGHTLIB)/mini_cpp.cpp
endif
ifeq ($(DEBUG), YES)
SRC += $(FLIGHTLIB)/dcc_stdio.c
SRC += $(FLIGHTLIB)/cm3_fault_handlers.c
endif
## Modules
SRC += $(foreach mod, $(MODULES), $(sort $(wildcard $(OPMODULEDIR)/$(mod)/*.c)))
CPPSRC += $(foreach mod, $(MODULES), $(sort $(wildcard $(OPMODULEDIR)/$(mod)/*.cpp)))

View File

@ -34,14 +34,16 @@ FLIGHTLIBINC = $(FLIGHTLIB)/inc
override USE_DSP_LIB := NO
## PIOS Hardware
ifeq ($(MCU),cortex-m3)
ifneq (,$(findstring STM32F10,$(CHIP)))
include $(PIOS)/stm32f10x/library.mk
else ifeq ($(MCU),cortex-m4)
else ifneq (,$(findstring STM32F4,$(CHIP)))
include $(PIOS)/stm32f4xx/library.mk
else ifeq ($(MCU),cortex-m0)
else ifneq (,$(findstring STM32F30,$(CHIP)))
include $(PIOS)/stm32f30x/library.mk
else ifneq (,$(findstring STM32F0,$(CHIP)))
include $(PIOS)/stm32f0x/library.mk
else
$(error Unsupported MCU: $(MCU))
$(error Unsupported CHIP: $(CHIP))
endif
# List C source files here (C dependencies are automatically generated).

View File

@ -152,6 +152,14 @@ ifdef USER_EE_BANK_BASE
BOARD_CDEFS += -DUSER_EE_BANK_BASE=$(USER_EE_BANK_BASE)
BOARD_CDEFS += -DUSER_EE_BANK_SIZE=$(USER_EE_BANK_SIZE)
endif
ifdef SRAM_BANK_BASE
BOARD_CDEFS += -DSRAM_BANK_BASE=$(SRAM_BANK_BASE)
BOARD_CDEFS += -DSRAM_BANK_SIZE=$(SRAM_BANK_SIZE)
endif
ifdef CCSRAM_BANK_BASE
BOARD_CDEFS += -DCCSRAM_BANK_BASE=$(CCSRAM_BANK_BASE)
BOARD_CDEFS += -DCCSRAM_BANK_SIZE=$(CCSRAM_BANK_SIZE)
endif
CDEFS += $(BOARD_CDEFS)
ifeq ($(DEBUG), YES)
@ -214,6 +222,8 @@ ALLSRCBASE = $(notdir $(basename $(ALLSRC)))
# Define all object files.
ALLOBJ = $(addprefix $(OUTDIR)/, $(addsuffix .o, $(ALLSRCBASE))) $(EXTRAOBJ)
ALLLD = $(addprefix $(OUTDIR)/, $(addsuffix .ld, $(notdir $(basename $(LDSRC)))))
# Define all listing files (used for make clean).
LSTFILES = $(addprefix $(OUTDIR)/, $(addsuffix .lst, $(ALLSRCBASE)))
# Define all depedency-files (used for make clean).
@ -241,9 +251,9 @@ endif
# Link: create ELF output file from object files.
ifeq ($(USE_CXX), YES)
$(eval $(call LINK_CXX_TEMPLATE,$(OUTDIR)/$(TARGET).elf,$(ALLOBJ),$(ALLLIB)))
$(eval $(call LINK_CXX_TEMPLATE,$(OUTDIR)/$(TARGET).elf,$(ALLOBJ),$(ALLLIB),$(ALLLD)))
else
$(eval $(call LINK_TEMPLATE,$(OUTDIR)/$(TARGET).elf,$(ALLOBJ),$(ALLLIB)))
$(eval $(call LINK_TEMPLATE,$(OUTDIR)/$(TARGET).elf,$(ALLOBJ),$(ALLLIB),$(ALLLD)))
endif
# Assemble: create object files from assembler source files.
@ -272,6 +282,9 @@ $(eval $(call PARTIAL_COMPILE_TEMPLATE,SRC))
# Compile: create assembler files from C source files. ARM only
$(eval $(call PARTIAL_COMPILE_ARM_TEMPLATE,SRCARM))
# Preprocess: create linker scripts from .lds files.
$(foreach src, $(LDSRC), $(eval $(call PREPROCESS_LDS_TEMPLATE,$(src))))
# Add opfw target
$(eval $(call OPFW_TEMPLATE,$(OUTDIR)/$(TARGET).bin,$(BOARD_TYPE),$(BOARD_REVISION)))

View File

@ -67,6 +67,7 @@ MSG_JTAG_PROGRAM = $(QUOTE) JTAG-PGM $(MSG_EXTRA) $(QUOTE)
MSG_JTAG_WIPE = $(QUOTE) JTAG-WIPE $(MSG_EXTRA) $(QUOTE)
MSG_PADDING = $(QUOTE) PADDING $(MSG_EXTRA) $(QUOTE)
MSG_FLASH_IMG = $(QUOTE) FLASH_IMG $(MSG_EXTRA) $(QUOTE)
MSG_PREPROCESSING_LDS = $(QUOTE) PP $(MSG_EXTRA) $(QUOTE)
# Function for converting an absolute path to one relative
# to the top of the source tree.
@ -175,6 +176,13 @@ $(OUTDIR)/$(notdir $(basename $(1))).o : $(1)
$(V1) $(CC) -c $(THUMB) $$(CFLAGS) $$(CONLYFLAGS) $$(CPPFLAGS) $$< -o $$@
endef
# Preprocess: create linker scripts from .lds files.
define PREPROCESS_LDS_TEMPLATE
$(OUTDIR)/$(notdir $(basename $(1))).ld : $(1)
@echo $(MSG_PREPROCESSING_LDS) $$(call toprel, $$<)
$(V1) $(CXX) -E -P -x c $(THUMB) $$(CFLAGS) $$(CPPFLAGS) $$< -o $$@
endef
# Compile: create object files from C source files. ARM-only
define COMPILE_C_ARM_TEMPLATE
$(OUTDIR)/$(notdir $(basename $(1))).o : $(1)
@ -224,13 +232,16 @@ endef
# $1 = elf file to produce
# $2 = list of object files that make up the elf file
# $3 = optional list of libraries to build and link
# $4 = optional list of linker scripts to build and link
define LINK_TEMPLATE
.SECONDARY : $(1)
.PRECIOUS : $(2) $(3)
$(1).input_files: $(2) $(3)
.PRECIOUS : $(2) $(3) $(4)
$(1).input_files: $(2) $(3) $(4)
$(V1) rm -rf $(1).input_files
$(foreach file,$(2) $(3),
$(V1) echo $(file) >> $$@)
$(foreach file,$(4),
$(V1) echo -T$(file) >> $$@)
$(1): $(1).input_files
@echo $(MSG_LINKING) $$(call toprel, $$@)
@ -240,13 +251,17 @@ endef
# Link: create ELF output file from object files.
# $1 = elf file to produce
# $2 = list of object files that make up the elf file
# $3 = optional list of libraries to build and link
# $4 = optional list of linker scripts to build and link
define LINK_CXX_TEMPLATE
.SECONDARY : $(1)
.PRECIOUS : $(2) $(3)
$(1).input_files: $(2) $(3)
.PRECIOUS : $(2) $(3) $(4)
$(1).input_files: $(2) $(3) $(4)
$(V1) rm -rf $(1).input_files
$(foreach file,$(2) $(3),
$(V1) echo $(file) >> $$@)
$(foreach file,$(4),
$(V1) echo -T$(file) >> $$@)
$(1): $(1).input_files
@echo $(MSG_LINKING) $$(call toprel, $$@)

View File

@ -66,12 +66,21 @@
// Private variables
static bool batteryEnabled = false;
#ifndef PIOS_ADC_VOLTAGE_PIN
#define PIOS_ADC_VOLTAGE_PIN -1
#endif
#ifndef PIOS_ADC_CURRENT_PIN
#define PIOS_ADC_CURRENT_PIN -1
#endif
// THESE COULD BE BETTER AS SOME KIND OF UNION OR STRUCT, BY WHICH 4 BITS ARE USED FOR EACH
// PIN VARIABLE, ONE OF WHICH INDICATES SIGN, AND THE OTHER 3 BITS INDICATE POSITION. THIS WILL
// WORK FOR QUITE SOMETIME, UNTIL MORE THAN 8 ADC ARE AVAILABLE. EVEN AT THIS POINT, THE STRUCTURE
// CAN SIMPLY BE MODIFIED TO SUPPORT 15 ADC PINS, BY USING ALL AVAILABLE BITS.
static int8_t voltageADCPin = -1; // ADC pin for voltage
static int8_t currentADCPin = -1; // ADC pin for current
static int8_t voltageADCPin = PIOS_ADC_VOLTAGE_PIN; // ADC pin for voltage
static int8_t currentADCPin = PIOS_ADC_CURRENT_PIN; // ADC pin for current
// Private functions
static void onTimer(UAVObjEvent *ev);
@ -87,11 +96,10 @@ int32_t BatteryInitialize(void)
batteryEnabled = true;
#else
HwSettingsInitialize();
uint8_t optionalModules[HWSETTINGS_OPTIONALMODULES_NUMELEM];
HwSettingsOptionalModulesData optionalModules;
HwSettingsOptionalModulesGet(&optionalModules);
HwSettingsOptionalModulesGet(optionalModules);
if ((optionalModules[HWSETTINGS_OPTIONALMODULES_BATTERY] == HWSETTINGS_OPTIONALMODULES_ENABLED)) {
if (optionalModules.Battery == HWSETTINGS_OPTIONALMODULES_ENABLED) {
batteryEnabled = true;
} else {
batteryEnabled = false;
@ -149,17 +157,19 @@ static void onTimer(__attribute__((unused)) UAVObjEvent *ev)
batterySettings.ResetConsumedEnergy = false;
FlightBatterySettingsSet(&batterySettings);
}
#ifdef PIOS_INCLUDE_ADC
// calculate the battery parameters
if (voltageADCPin >= 0) {
flightBatteryData.Voltage = (PIOS_ADC_PinGetVolt(voltageADCPin) - batterySettings.SensorCalibrations.VoltageZero) * batterySettings.SensorCalibrations.VoltageFactor; // in Volts
} else {
flightBatteryData.Voltage = 0; // Dummy placeholder value. This is in case we get another source of battery current which is not from the ADC
}
#else
flightBatteryData.Voltage = 0;
#endif /* PIOS_INCLUDE_ADC */
// voltage available: get the number of cells if possible, desired and not armed
GetNbCells(&batterySettings, &flightBatteryData);
#ifdef PIOS_INCLUDE_ADC
// ad a plausibility check: zero voltage => zero current
if (currentADCPin >= 0 && flightBatteryData.Voltage > 0.f) {
flightBatteryData.Current = (PIOS_ADC_PinGetVolt(currentADCPin) - batterySettings.SensorCalibrations.CurrentZero) * batterySettings.SensorCalibrations.CurrentFactor; // in Amps
@ -169,6 +179,9 @@ static void onTimer(__attribute__((unused)) UAVObjEvent *ev)
} else { // If there's no current measurement, we still need to assign one. Make it negative, so it can never trigger an alarm
flightBatteryData.Current = -0; // Dummy placeholder value. This is in case we get another source of battery current which is not from the ADC
}
#else
flightBatteryData.Current = -0;
#endif /* PIOS_INCLUDE_ADC */
// For safety reasons consider only positive currents in energy comsumption, i.e. no charging up.
// necesary when sensor are not perfectly calibrated

View File

@ -37,7 +37,6 @@
#include "inc/notify.h"
#include "inc/sequences.h"
#include <pios_mem.h>
#include <hwsettings.h>
#define SAMPLE_PERIOD_MS 250
// private types
@ -54,13 +53,7 @@ static void checkAlarm(uint8_t alarm, uint8_t *last_alarm, uint32_t *last_alm_ti
static AlarmStatus_t *alarmStatus;
int32_t NotifyInitialize(void)
{
uint8_t ws281xOutStatus;
HwSettingsWS2811LED_OutGet(&ws281xOutStatus);
// Todo: Until further applications exists for WS2811 notify enabled status is tied to ws281x output configuration
bool enabled = ws281xOutStatus != HWSETTINGS_WS2811LED_OUT_DISABLED;
if (enabled) {
if (PIOS_WS2811_DEVICE) {
alarmStatus = (AlarmStatus_t *)pios_malloc(sizeof(AlarmStatus_t) * alarmsMapSize);
for (uint8_t i = 0; i < alarmsMapSize; i++) {
alarmStatus[i].lastAlarm = SYSTEMALARMS_ALARM_OK;

View File

@ -63,7 +63,6 @@
#include <auxmagsupport.h>
#include <accelgyrosettings.h>
#include <revosettings.h>
#include <UBX.h>
#include <mathmisc.h>
#include <taskinfo.h>
@ -284,7 +283,7 @@ static void SensorsTask(__attribute__((unused)) void *parameters)
count++;
}
PIOS_Assert(count);
// PIOS_Assert(count);
RELOAD_WDG();
if (!sensors_test) {
AlarmsSet(SYSTEMALARMS_ALARM_SENSORS, SYSTEMALARMS_ALARM_CRITICAL);

View File

@ -165,6 +165,12 @@ static float gyroRaw[3];
static float gyroDelta[3];
// preconfigured filter chains selectable via revoSettings.FusionAlgorithm
static const filterPipeline *acroQueue = &(filterPipeline) {
.filter = &cfFilter,
.next = NULL,
};
static const filterPipeline *cfQueue = &(filterPipeline) {
.filter = &airFilter,
.next = &(filterPipeline) {
@ -434,6 +440,9 @@ static void StateEstimationCb(void)
if (fsarmed == FLIGHTSTATUS_ARMED_DISARMED || fusionAlgorithm == FILTER_INIT_FORCE) {
const filterPipeline *newFilterChain;
switch ((RevoSettingsFusionAlgorithmOptions)revoSettings.FusionAlgorithm) {
case REVOSETTINGS_FUSIONALGORITHM_ACRONOSENSORS:
newFilterChain = acroQueue;
break;
case REVOSETTINGS_FUSIONALGORITHM_BASICCOMPLEMENTARY:
newFilterChain = cfQueue;
// reinit Mag alarm

View File

@ -579,7 +579,11 @@ static uint16_t GetFreeIrqStackSize(void)
#if !defined(ARCH_POSIX) && !defined(ARCH_WIN32) && defined(CHECK_IRQ_STACK)
extern uint32_t _irq_stack_top;
extern uint32_t _irq_stack_end;
uint32_t pattern = 0x0000A5A5;
#ifdef STM32F3
uint32_t pattern = 0xA5A5A5A5;
#else
uint32_t pattern = 0xA5A5;
#endif
uint32_t *ptr = &_irq_stack_end;
#if 1 /* the ugly way accurate but takes more time, useful for debugging */

View File

@ -0,0 +1,20 @@
/*
* Since at least FreeRTOS V7.5.3 uxTopUsedPriority is no longer
* present in the kernel, so it has to be supplied by other means for
* OpenOCD's threads awareness.
*
* Add this file to your project, and, if you're using --gc-sections,
* ``--undefined=uxTopUsedPriority'' (or
* ``-Wl,--undefined=uxTopUsedPriority'' when using gcc for final
* linking) to your LDFLAGS; same with all the other symbols you need.
*/
#include "FreeRTOS.h"
#ifdef __GNUC__
#define USED __attribute__((section(".keep")))
#else
#define USED
#endif
const int USED uxTopUsedPriority = configMAX_PRIORITIES;

View File

@ -81,6 +81,9 @@ pios_general_malloc(void *ptr, size_t s, bool use_fast_heap)
vPortEnterCritical();
if(use_fast_heap){
p = msheap_alloc(&fast_heap, ptr, s);
if(!p) {
p = msheap_alloc(&sram_heap, ptr, s);
}
} else {
p = msheap_alloc(&sram_heap, ptr, s);
}

View File

@ -0,0 +1,405 @@
/**
******************************************************************************
* @addtogroup PIOS PIOS Core hardware abstraction layer
* @{
* @addtogroup PIOS_BMP280 BMP280 Functions
* @brief Hardware functions to deal with the altitude pressure sensor
* @{
*
* @file pios_bmp280.c
* @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017.
* @brief BMP280 Pressure Sensor Routines
* @see The GNU Public License (GPL) Version 3
*
******************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "pios.h"
#ifdef PIOS_INCLUDE_BMP280
#include <pios_bmp280.h>
#include <pios_i2c.h>
#define BMP280_I2C_ADDR 0x76
#define BMP280_ID 0xD0
#define BMP280_RESET 0xE0
#define BMP280_STATUS 0xF3
#define BMP280_CTRL_MEAS 0xF4
#define BMP280_CONFIG 0xF5
#define BMP280_PRESS_MSB 0xF7
#define BMP280_PRESS_LSB 0xF8
#define BMP280_PRESS_XLSB 0xF9
#define BMP280_TEMP_MSB 0xFA
#define BMP280_TEMP_LSB 0xFB
#define BMP280_TEMP_XLSB 0xFC
#define BMP280_CAL_ADDR 0x88
#define BMP280_P0 101.3250f
#define BMP280_MODE_CONTINUOUS 0x03
#define BMP280_MODE_STANDBY 0x00
#define BMP280_MODE_FORCED 0x01
#define BMP280_T_STANDBY 500
#define BMP280_DEFAULT_CHIP_ID 0x58
#define BMP280_RESET_MAGIC 0xB6
#define BMP280_PRESSURE_TEMPERATURE_CALIB_DATA_LENGTH 24
#define BMP280_DATA_FRAME_SIZE 6
#define PIOS_BMP280_I2C_RETRIES 5
#define PIOS_BMP280_I2C_CONFIG_RETRY_DELAY 1000000
enum pios_bmp280_dev_magic {
PIOS_BMP280_DEV_MAGIC = 0x42323830
};
struct pios_bmp280_dev {
enum pios_bmp280_dev_magic magic;
uintptr_t i2c_id;
bool sensorIsAlive;
uint32_t conversionDelayUs;
uint32_t configTime;
uint32_t conversionStart;
uint8_t oversampling;
// compensation parameters
uint16_t digT1;
int16_t digT2;
int16_t digT3;
uint16_t digP1;
int16_t digP2;
int16_t digP3;
int16_t digP4;
int16_t digP5;
int16_t digP6;
int16_t digP7;
int16_t digP8;
int16_t digP9;
PIOS_SENSORS_1Axis_SensorsWithTemp results;
};
static int32_t PIOS_BMP280_Read(uintptr_t i2c_id, uint8_t address, uint8_t *buffer, uint8_t len);
static int32_t PIOS_BMP280_Write(uintptr_t i2c_id, uint8_t address, uint8_t buffer);
static int32_t PIOS_BMP280_Configure(struct pios_bmp280_dev *dev);
static int32_t PIOS_BMP280_ReadPTCompensated(struct pios_bmp280_dev *dev,
uint32_t *compensatedPressure,
int32_t *compensatedTemperature);
// sensor driver interface
static bool PIOS_BMP280_driver_Test(uintptr_t context);
static void PIOS_BMP280_driver_Reset(uintptr_t context);
static void PIOS_BMP280_driver_get_scale(float *scales, uint8_t size, uintptr_t context);
static void PIOS_BMP280_driver_fetch(void *, uint8_t size, uintptr_t context);
static bool PIOS_BMP280_driver_poll(uintptr_t context);
const PIOS_SENSORS_Driver PIOS_BMP280_Driver = {
.test = PIOS_BMP280_driver_Test,
.poll = PIOS_BMP280_driver_poll,
.fetch = PIOS_BMP280_driver_fetch,
.reset = PIOS_BMP280_driver_Reset,
.get_queue = NULL,
.get_scale = PIOS_BMP280_driver_get_scale,
.is_polled = true,
};
static bool PIOS_BMP280_Validate(struct pios_bmp280_dev *dev)
{
return dev && (dev->magic == PIOS_BMP280_DEV_MAGIC);
}
/**
* Initialise the BMP280 sensor
*/
void PIOS_BMP280_Init(const struct pios_bmp280_cfg *cfg, uint32_t i2c_device)
{
struct pios_bmp280_dev *dev = (struct pios_bmp280_dev *)pios_malloc(sizeof(*dev));
PIOS_Assert(dev);
dev->magic = PIOS_BMP280_DEV_MAGIC;
dev->i2c_id = i2c_device;
dev->sensorIsAlive = false;
dev->oversampling = cfg->oversampling;
switch (cfg->oversampling) {
case BMP280_STANDARD_RESOLUTION:
dev->conversionDelayUs = 13300 + BMP280_T_STANDBY;
break;
case BMP280_HIGH_RESOLUTION:
dev->conversionDelayUs = 22500 + BMP280_T_STANDBY;
break;
default:
case BMP280_ULTRA_HIGH_RESOLUTION:
dev->conversionDelayUs = 43200 + BMP280_T_STANDBY;
break;
}
PIOS_BMP280_Configure(dev);
PIOS_SENSORS_Register(&PIOS_BMP280_Driver, PIOS_SENSORS_TYPE_1AXIS_BARO, (uintptr_t)dev);
}
static int32_t PIOS_BMP280_Configure(struct pios_bmp280_dev *dev)
{
// read chip id?
uint8_t chip_id;
if (dev->sensorIsAlive) {
return 0;
}
if (PIOS_DELAY_DiffuS(dev->configTime) < PIOS_BMP280_I2C_CONFIG_RETRY_DELAY) { // Do not reinitialize too often
return -1;
}
dev->configTime = PIOS_DELAY_GetRaw();
dev->sensorIsAlive = (PIOS_BMP280_Read(dev->i2c_id, BMP280_ID, &chip_id, sizeof(chip_id)) == 0);
if (!dev->sensorIsAlive) {
return -1;
}
if (chip_id != BMP280_DEFAULT_CHIP_ID) {
return -2;
}
uint8_t data[BMP280_PRESSURE_TEMPERATURE_CALIB_DATA_LENGTH];
dev->sensorIsAlive = (PIOS_BMP280_Read(dev->i2c_id, BMP280_CAL_ADDR, data, BMP280_PRESSURE_TEMPERATURE_CALIB_DATA_LENGTH) == 0);
if (!dev->sensorIsAlive) {
return -1;
}
dev->digT1 = (data[1] << 8) | data[0];
dev->digT2 = (data[3] << 8) | data[2];
dev->digT3 = (data[5] << 8) | data[4];
dev->digP1 = (data[7] << 8) | data[6];
dev->digP2 = (data[9] << 8) | data[8];
dev->digP3 = (data[11] << 8) | data[10];
dev->digP4 = (data[13] << 8) | data[12];
dev->digP5 = (data[15] << 8) | data[14];
dev->digP6 = (data[17] << 8) | data[16];
dev->digP7 = (data[19] << 8) | data[18];
dev->digP8 = (data[21] << 8) | data[20];
dev->digP9 = (data[23] << 8) | data[22];
dev->sensorIsAlive = (PIOS_BMP280_Write(dev->i2c_id, BMP280_RESET, BMP280_RESET_MAGIC) == 0);
if (!dev->sensorIsAlive) {
return -1;
}
/* start conversion */
dev->sensorIsAlive = (PIOS_BMP280_Write(dev->i2c_id, BMP280_CTRL_MEAS, dev->oversampling | BMP280_MODE_CONTINUOUS) == 0);
dev->conversionStart = PIOS_DELAY_GetRaw();
return 0;
}
static int32_t PIOS_BMP280_ReadPTCompensated(struct pios_bmp280_dev *dev,
uint32_t *compensatedPressure,
int32_t *compensatedTemperature)
{
uint8_t data[BMP280_DATA_FRAME_SIZE];
/* Read and store results */
if (PIOS_BMP280_Read(dev->i2c_id, BMP280_PRESS_MSB, data, BMP280_DATA_FRAME_SIZE) != 0) {
return -1;
}
static int32_t T = 0;
int32_t raw_temperature = (int32_t)((((uint32_t)(data[3])) << 12) | (((uint32_t)(data[4])) << 4) | ((uint32_t)data[5] >> 4));
int32_t varT1, varT2;
varT1 = ((((raw_temperature >> 3) - ((int32_t)dev->digT1 << 1))) * ((int32_t)dev->digT2)) >> 11;
varT2 = (((((raw_temperature >> 4) - ((int32_t)dev->digT1)) * ((raw_temperature >> 4) - ((int32_t)dev->digT1))) >> 12) * ((int32_t)dev->digT3)) >> 14;
/* Filter T ourselves */
if (!T) {
T = (varT1 + varT2) * 5;
} else {
T = (varT1 + varT2) + (T * 4) / 5; // IIR Gain=5
}
*compensatedTemperature = T;
int32_t raw_pressure = (int32_t)((((uint32_t)(data[0])) << 12) | (((uint32_t)(data[1])) << 4) | ((uint32_t)data[2] >> 4));
if (raw_pressure == 0x80000) {
return 1;
}
int64_t varP1, varP2, P;
varP1 = ((int64_t)T / 5) - 128000;
varP2 = varP1 * varP1 * (int64_t)dev->digP6;
varP2 = varP2 + ((varP1 * (int64_t)dev->digP5) << 17);
varP2 = varP2 + (((int64_t)dev->digP4) << 35);
varP1 = ((varP1 * varP1 * (int64_t)dev->digP3) >> 8) + ((varP1 * (int64_t)dev->digP2) << 12);
varP1 = (((((int64_t)1) << 47) + varP1)) * ((int64_t)dev->digP1) >> 33;
if (varP1 == 0) {
return 1; // avoid exception caused by division by zero
}
P = 1048576 - raw_pressure;
P = (((P << 31) - varP2) * 3125) / varP1;
varP1 = (((int64_t)dev->digP9) * (P >> 13) * (P >> 13)) >> 25;
varP2 = (((int64_t)dev->digP8) * P) >> 19;
*compensatedPressure = (uint32_t)((P + varP1 + varP2) >> 8) + (((int64_t)dev->digP7) << 4);
return 0;
}
/**
* Reads one or more bytes into a buffer
* \param[in] the command indicating the address to read
* \param[out] buffer destination buffer
* \param[in] len number of bytes which should be read
* \return 0 if operation was successful
* \return -1 if error during I2C transfer
*/
static int32_t PIOS_BMP280_Read(uintptr_t i2c_id, uint8_t address, uint8_t *buffer, uint8_t len)
{
const struct pios_i2c_txn txn_list[] = {
{
.info = __func__,
.addr = BMP280_I2C_ADDR,
.rw = PIOS_I2C_TXN_WRITE,
.len = 1,
.buf = &address,
}
,
{
.info = __func__,
.addr = BMP280_I2C_ADDR,
.rw = PIOS_I2C_TXN_READ,
.len = len,
.buf = buffer,
}
};
for (uint8_t retry = PIOS_BMP280_I2C_RETRIES; retry > 0; --retry) {
if (PIOS_I2C_Transfer(i2c_id, txn_list, NELEMENTS(txn_list)) == 0) {
return 0;
}
}
return -1;
}
static int32_t PIOS_BMP280_Write(uintptr_t i2c_id, uint8_t address, uint8_t value)
{
uint8_t data[] = { address, value };
const struct pios_i2c_txn txn_list[] = {
{
.info = __func__,
.addr = BMP280_I2C_ADDR,
.rw = PIOS_I2C_TXN_WRITE,
.len = sizeof(data),
.buf = data,
}
};
for (uint8_t retry = PIOS_BMP280_I2C_RETRIES; retry > 0; --retry) {
if (PIOS_I2C_Transfer(i2c_id, txn_list, NELEMENTS(txn_list)) == 0) {
return 0;
}
}
return -1;
}
bool PIOS_BMP280_driver_Test(__attribute__((unused)) uintptr_t context)
{
return true;
}
static void PIOS_BMP280_driver_Reset(__attribute__((unused)) uintptr_t context)
{}
static void PIOS_BMP280_driver_get_scale(float *scales, uint8_t size, __attribute__((unused)) uintptr_t context)
{
PIOS_Assert(size > 0);
scales[0] = 1;
}
static void PIOS_BMP280_driver_fetch(void *data, __attribute__((unused)) uint8_t size, uintptr_t context)
{
struct pios_bmp280_dev *dev = (struct pios_bmp280_dev *)context;
PIOS_Assert(PIOS_BMP280_Validate(dev));
PIOS_Assert(data);
memcpy(data, (void *)&dev->results, sizeof(PIOS_SENSORS_1Axis_SensorsWithTemp));
}
static bool PIOS_BMP280_driver_poll(uintptr_t context)
{
struct pios_bmp280_dev *dev = (struct pios_bmp280_dev *)context;
PIOS_Assert(PIOS_BMP280_Validate(dev));
if (!dev->sensorIsAlive) {
if (PIOS_BMP280_Configure(dev) < 0) {
return false;
}
}
if (PIOS_DELAY_DiffuS(dev->conversionStart) < dev->conversionDelayUs) {
return false;
}
dev->conversionStart = PIOS_DELAY_GetRaw();
uint32_t cP = 0;
int32_t cT = 0;
int32_t res = PIOS_BMP280_ReadPTCompensated(dev, &cP, &cT);
dev->sensorIsAlive = (res >= 0);
if (res != 0) {
return false;
}
dev->results.temperature = ((float)cT) / 256.0f / 100.0f;
dev->results.sample = ((float)cP) / 256.0f;
return true;
}
#endif /* PIOS_INCLUDE_BMP280 */
/**
* @}
* @}
*/

View File

@ -233,7 +233,7 @@ void PIOS_BOARD_IO_Configure_USB_Function(PIOS_BOARD_IO_USB_HID_Function hid_fun
#endif /* PIOS_INCLUDE_USB_HID */
#ifndef STM32F10X
#if !defined(STM32F1) && !defined(STM32F3)
PIOS_USBHOOK_Activate();
#endif
}
@ -266,8 +266,6 @@ static int32_t PIOS_DSM_Init_Helper(uint32_t *id, const struct pios_com_driver *
# ifdef PIOS_INCLUDE_SBUS
static int32_t PIOS_SBus_Init_Helper(uint32_t *id, const struct pios_com_driver *driver, uint32_t lower_id)
{
// sbus-noninverted
HwSettingsSBusModeOptions hwsettings_SBusMode;
HwSettingsSBusModeGet(&hwsettings_SBusMode);
@ -278,7 +276,23 @@ static int32_t PIOS_SBus_Init_Helper(uint32_t *id, const struct pios_com_driver
return PIOS_SBus_Init(id, &sbus_cfg, driver, lower_id);
}
# endif
static int32_t PIOS_SBus_Normal_Init_Helper(uint32_t *id, const struct pios_com_driver *driver, uint32_t lower_id)
{
struct pios_sbus_cfg sbus_cfg = {
.non_inverted = false,
};
return PIOS_SBus_Init(id, &sbus_cfg, driver, lower_id);
}
static int32_t PIOS_SBus_Not_Inverted_Init_Helper(uint32_t *id, const struct pios_com_driver *driver, uint32_t lower_id)
{
struct pios_sbus_cfg sbus_cfg = {
.non_inverted = true,
};
return PIOS_SBus_Init(id, &sbus_cfg, driver, lower_id);
}
# endif /* ifdef PIOS_INCLUDE_SBUS */
#endif /* ifdef PIOS_INCLUDE_RCVR */
struct uart_function {
@ -325,7 +339,6 @@ static const struct uart_function uart_function_map[] = {
#ifdef PIOS_INCLUDE_FRSKY_SENSORHUB
[PIOS_BOARD_IO_UART_FRSKY_SENSORHUB] = {
.com_id = &pios_com_frsky_sensorhub_id,
.com_rx_buf_len = PIOS_COM_FRSKY_SENSORHUB_RX_BUF_LEN,
.com_tx_buf_len = PIOS_COM_FRSKY_SENSORHUB_TX_BUF_LEN,
},
#endif
@ -407,6 +420,16 @@ static const struct uart_function uart_function_map[] = {
.rcvr_driver = &pios_sbus_rcvr_driver,
.rcvr_group = MANUALCONTROLSETTINGS_CHANNELGROUPS_SBUS,
},
[PIOS_BOARD_IO_UART_SBUS_NORMAL] = {
.rcvr_init = &PIOS_SBus_Normal_Init_Helper,
.rcvr_driver = &pios_sbus_rcvr_driver,
.rcvr_group = MANUALCONTROLSETTINGS_CHANNELGROUPS_SBUS,
},
[PIOS_BOARD_IO_UART_SBUS_NOT_INVERTED] = {
.rcvr_init = &PIOS_SBus_Not_Inverted_Init_Helper,
.rcvr_driver = &pios_sbus_rcvr_driver,
.rcvr_group = MANUALCONTROLSETTINGS_CHANNELGROUPS_SBUS,
},
# endif /* PIOS_INCLUDE_SBUS */
#endif /* PIOS_INCLUDE_RCVR */
};
@ -460,6 +483,12 @@ void PIOS_BOARD_IO_Configure_UART(const struct pios_usart_cfg *hw_config, PIOS_B
PIOS_Assert(0);
}
/* lock uart config */
if (pios_usart_com_driver.ioctl) {
bool lock = true;
pios_usart_com_driver.ioctl(usart_id, PIOS_IOCTL_USART_LOCK_CONFIG, &lock);
}
pios_rcvr_group_map[uart_function_map[function].rcvr_group] = rcvr_id;
}
#endif /* PIOS_INCLUDE_RCVR */
@ -672,7 +701,6 @@ void PIOS_BOARD_IO_Configure_RFM22B()
OPLinkStatusSet(&oplinkStatus);
}
void PIOS_BOARD_IO_Configure_RadioAuxStream(HwSettingsRadioAuxStreamOptions radioaux)
{
switch (radioaux) {

View File

@ -42,6 +42,10 @@
# include <pios_ms5611.h>
#endif
#ifdef PIOS_INCLUDE_BMP280
# include <pios_bmp280.h>
#endif
#ifdef PIOS_INCLUDE_ADXL345
# include <pios_adxl345.h>
#endif
@ -75,7 +79,13 @@ void PIOS_BOARD_Sensors_Configure()
#ifdef PIOS_INCLUDE_MPU6000
const struct pios_mpu6000_cfg *mpu6000_cfg = PIOS_BOARD_HW_DEFS_GetMPU6000Cfg(pios_board_info_blob.board_rev);
if (mpu6000_cfg) {
#ifdef PIOS_SPI_MPU6000_ADAPTER
PIOS_MPU6000_Init(PIOS_SPI_MPU6000_ADAPTER, 0, mpu6000_cfg);
#elif defined(PIOS_I2C_MPU6000_ADAPTER)
PIOS_MPU6000_Init(PIOS_I2C_MPU6000_ADAPTER, 0, mpu6000_cfg);
#else
#error PIOS_INCLUDE_MPU6000 requires one of PIOS_SPI_MPU6000_ADAPTER or PIOS_I2C_MPU6000_ADAPTER
#endif
PIOS_MPU6000_CONFIG_Configure();
#ifndef PIOS_EXCLUDE_ADVANCED_FEATURES
PIOS_MPU6000_Register();
@ -151,10 +161,14 @@ void PIOS_BOARD_Sensors_Configure()
if (option == AUXMAGSETTINGS_TYPE_FLEXI) {
// i2c_external
#ifdef PIOS_I2C_EXTERNAL_ADAPTER
i2c_id = PIOS_I2C_EXTERNAL_ADAPTER;
#endif
} else if (option == AUXMAGSETTINGS_TYPE_I2C) {
// i2c_internal (or Sparky2/F3 dedicated I2C port)
#ifdef PIOS_I2C_FLEXI_ADAPTER
i2c_id = PIOS_I2C_FLEXI_ADAPTER;
#endif
}
if (i2c_id) {
@ -184,6 +198,13 @@ void PIOS_BOARD_Sensors_Configure()
}
#endif
#ifdef PIOS_INCLUDE_BMP280
const struct pios_bmp280_cfg *bmp280_cfg = PIOS_BOARD_HW_DEFS_GetBMP280Cfg(pios_board_info_blob.board_rev);
if (bmp280_cfg) {
PIOS_BMP280_Init(bmp280_cfg, PIOS_I2C_BMP280_INTERNAL_ADAPTER);
}
#endif
#ifdef PIOS_INCLUDE_ADC
const struct pios_adc_cfg *adc_cfg = PIOS_BOARD_HW_DEFS_GetAdcCfg(pios_board_info_blob.board_rev);
if (adc_cfg) {
@ -200,15 +221,9 @@ void PIOS_BOARD_Sensors_Configure()
}
#endif /* PIOS_INCLUDE_ADC */
// internal bmp280 baro
// internal MPU6000 imu (i2c)
// external ETASV3 Eagletree Airspeed v3
// external MS4525D PixHawk Airpeed based on MS4525DO
// BMA180 accelerometer?
// bmp085/bmp180 baro
// hmc5843 mag
// i2c esc (?)
// UBX DCC

View File

@ -72,7 +72,7 @@ static struct pios_com_dev *PIOS_COM_alloc(void)
{
struct pios_com_dev *com_dev;
com_dev = (struct pios_com_dev *)pios_malloc(sizeof(struct pios_com_dev));
com_dev = (struct pios_com_dev *)pios_fastheapmalloc(sizeof(struct pios_com_dev));
if (!com_dev) {
return NULL;
}
@ -120,14 +120,14 @@ int32_t PIOS_COM_Init(uint32_t *com_id, const struct pios_com_driver *driver, ui
if ((rx_buffer_len > 0) && !rx_buffer) {
#if defined(PIOS_INCLUDE_FREERTOS)
rx_buffer = (uint8_t *)pios_malloc(rx_buffer_len);
rx_buffer = (uint8_t *)pios_fastheapmalloc(rx_buffer_len);
#endif
PIOS_Assert(rx_buffer);
}
if ((tx_buffer_len > 0) && !tx_buffer) {
#if defined(PIOS_INCLUDE_FREERTOS)
tx_buffer = (uint8_t *)pios_malloc(tx_buffer_len);
tx_buffer = (uint8_t *)pios_fastheapmalloc(tx_buffer_len);
#endif
PIOS_Assert(tx_buffer);
}

View File

@ -31,7 +31,7 @@
#include "pios.h"
#ifdef PIOS_INCLUDE_FLASH
#if defined(PIOS_INCLUDE_FLASH) && defined(PIOS_INCLUDE_SPI)
#include "pios_flash_jedec_priv.h"
#include "pios_flash_jedec_catalog.h"
@ -632,4 +632,4 @@ const struct pios_flash_driver pios_jedec_flash_driver = {
.read_data = PIOS_Flash_Jedec_ReadData,
};
#endif /* PIOS_INCLUDE_FLASH */
#endif /* PIOS_INCLUDE_FLASH && PIOS_INCLUDE_SPI */

View File

@ -35,6 +35,7 @@
#include <stdint.h>
#include <pios_constants.h>
#include <pios_sensors.h>
#include <pios_i2c.h>
/* Global Variables */
@ -42,6 +43,9 @@ enum pios_mpu6000_dev_magic {
PIOS_MPU6000_DEV_MAGIC = 0x9da9b3ed,
};
#define CALLBACK_TASK_STACKSIZE 256
// sensor driver interface
bool PIOS_MPU6000_driver_Test(uintptr_t context);
void PIOS_MPU6000_driver_Reset(uintptr_t context);
@ -58,13 +62,18 @@ const PIOS_SENSORS_Driver PIOS_MPU6000_Driver = {
.is_polled = false,
};
//
struct pios_mpu6000_io_driver {
int32_t (*SetReg)(uint8_t address, uint8_t buffer);
int32_t (*GetReg)(uint8_t address);
bool (*ReadSensor)(bool *woken);
};
struct mpu6000_dev {
uint32_t spi_id;
uint32_t port_id;
uint32_t slave_num;
QueueHandle_t queue;
const struct pios_mpu6000_cfg *cfg;
struct pios_mpu6000_io_driver *driver;
enum pios_mpu6000_range gyro_range;
enum pios_mpu6000_accel_range accel_range;
enum pios_mpu6000_filter filter;
@ -101,6 +110,7 @@ typedef union {
static struct mpu6000_dev *dev;
volatile bool mpu6000_configured = false;
static mpu6000_data_t mpu6000_data;
static uint32_t gyro_read_timestamp;
static PIOS_SENSORS_3Axis_SensorsWithTemp *queue_data = 0;
#define SENSOR_COUNT 2
#define SENSOR_DATA_SIZE (sizeof(PIOS_SENSORS_3Axis_SensorsWithTemp) + sizeof(Vector3i16) * SENSOR_COUNT)
@ -109,12 +119,33 @@ static PIOS_SENSORS_3Axis_SensorsWithTemp *queue_data = 0;
static struct mpu6000_dev *PIOS_MPU6000_alloc(const struct pios_mpu6000_cfg *cfg);
static int32_t PIOS_MPU6000_Validate(struct mpu6000_dev *dev);
static void PIOS_MPU6000_Config(struct pios_mpu6000_cfg const *cfg);
static int32_t PIOS_MPU6000_SetReg(uint8_t address, uint8_t buffer);
static int32_t PIOS_MPU6000_GetReg(uint8_t address);
static void PIOS_MPU6000_SetSpeed(const bool fast);
static bool PIOS_MPU6000_HandleData(uint32_t gyro_read_timestamp);
static bool PIOS_MPU6000_ReadSensor(bool *woken);
#ifdef PIOS_INCLUDE_SPI
static int32_t PIOS_MPU6000_SPI_SetReg(uint8_t address, uint8_t buffer);
static int32_t PIOS_MPU6000_SPI_GetReg(uint8_t address);
static bool PIOS_MPU6000_SPI_ReadSensor(bool *woken);
static void PIOS_MPU6000_SetSpeed(const bool fast);
struct pios_mpu6000_io_driver spi_io_driver = {
.SetReg = PIOS_MPU6000_SPI_SetReg,
.GetReg = PIOS_MPU6000_SPI_GetReg,
.ReadSensor = PIOS_MPU6000_SPI_ReadSensor,
};
#endif /* PIOS_INCLUDE_SPI */
#ifdef PIOS_INCLUDE_I2C
static int32_t PIOS_MPU6000_I2C_SetReg(uint8_t address, uint8_t buffer);
static int32_t PIOS_MPU6000_I2C_GetReg(uint8_t address);
static bool PIOS_MPU6000_I2C_ReadSensor(bool *woken);
struct pios_mpu6000_io_driver i2c_io_driver = {
.SetReg = PIOS_MPU6000_I2C_SetReg,
.GetReg = PIOS_MPU6000_I2C_GetReg,
.ReadSensor = PIOS_MPU6000_I2C_ReadSensor,
};
#endif /* PIOS_INCLUDE_I2C */
static bool PIOS_MPU6000_HandleData(uint32_t gyro_read_timestamp);
static int32_t PIOS_MPU6000_Test(void);
void PIOS_MPU6000_Register()
@ -133,6 +164,20 @@ static struct mpu6000_dev *PIOS_MPU6000_alloc(const struct pios_mpu6000_cfg *cfg
mpu6000_dev->magic = PIOS_MPU6000_DEV_MAGIC;
if (cfg->i2c_addr == 0) {
#ifdef PIOS_INCLUDE_SPI
mpu6000_dev->driver = &spi_io_driver;
#else
PIOS_Assert(0)
#endif
} else {
#ifdef PIOS_INCLUDE_I2C
mpu6000_dev->driver = &i2c_io_driver;
#else
PIOS_Assert(0);
#endif
}
mpu6000_dev->queue = xQueueCreate(cfg->max_downsample + 1, SENSOR_DATA_SIZE);
PIOS_Assert(mpu6000_dev->queue);
@ -154,7 +199,7 @@ static int32_t PIOS_MPU6000_Validate(struct mpu6000_dev *vdev)
if (vdev->magic != PIOS_MPU6000_DEV_MAGIC) {
return -2;
}
if (vdev->spi_id == 0) {
if (vdev->port_id == 0) {
return -3;
}
return 0;
@ -164,14 +209,14 @@ static int32_t PIOS_MPU6000_Validate(struct mpu6000_dev *vdev)
* @brief Initialize the MPU6000 3-axis gyro sensor.
* @return 0 for success, -1 for failure
*/
int32_t PIOS_MPU6000_Init(uint32_t spi_id, uint32_t slave_num, const struct pios_mpu6000_cfg *cfg)
int32_t PIOS_MPU6000_Init(uint32_t port_id, uint32_t slave_num, const struct pios_mpu6000_cfg *cfg)
{
dev = PIOS_MPU6000_alloc(cfg);
if (dev == NULL) {
return -1;
}
dev->spi_id = spi_id;
dev->port_id = port_id;
dev->slave_num = slave_num;
dev->cfg = cfg;
@ -194,13 +239,13 @@ static void PIOS_MPU6000_Config(struct pios_mpu6000_cfg const *cfg)
PIOS_MPU6000_Test();
// Reset chip
while (PIOS_MPU6000_SetReg(PIOS_MPU6000_PWR_MGMT_REG, PIOS_MPU6000_PWRMGMT_IMU_RST) != 0) {
while (dev->driver->SetReg(PIOS_MPU6000_PWR_MGMT_REG, PIOS_MPU6000_PWRMGMT_IMU_RST) != 0) {
;
}
PIOS_DELAY_WaitmS(50);
// Reset chip and fifo
while (PIOS_MPU6000_SetReg(PIOS_MPU6000_USER_CTRL_REG,
while (dev->driver->SetReg(PIOS_MPU6000_USER_CTRL_REG,
PIOS_MPU6000_USERCTL_GYRO_RST |
PIOS_MPU6000_USERCTL_SIG_COND |
PIOS_MPU6000_USERCTL_FIFO_RST) != 0) {
@ -208,7 +253,7 @@ static void PIOS_MPU6000_Config(struct pios_mpu6000_cfg const *cfg)
}
// Wait for reset to finish
while (PIOS_MPU6000_GetReg(PIOS_MPU6000_USER_CTRL_REG) &
while (dev->driver->GetReg(PIOS_MPU6000_USER_CTRL_REG) &
(PIOS_MPU6000_USERCTL_GYRO_RST |
PIOS_MPU6000_USERCTL_SIG_COND |
PIOS_MPU6000_USERCTL_FIFO_RST)) {
@ -216,45 +261,45 @@ static void PIOS_MPU6000_Config(struct pios_mpu6000_cfg const *cfg)
}
PIOS_DELAY_WaitmS(10);
// Power management configuration
while (PIOS_MPU6000_SetReg(PIOS_MPU6000_PWR_MGMT_REG, cfg->Pwr_mgmt_clk) != 0) {
while (dev->driver->SetReg(PIOS_MPU6000_PWR_MGMT_REG, cfg->Pwr_mgmt_clk) != 0) {
;
}
// Interrupt configuration
while (PIOS_MPU6000_SetReg(PIOS_MPU6000_INT_CFG_REG, cfg->interrupt_cfg) != 0) {
while (dev->driver->SetReg(PIOS_MPU6000_INT_CFG_REG, cfg->interrupt_cfg) != 0) {
;
}
// Interrupt configuration
while (PIOS_MPU6000_SetReg(PIOS_MPU6000_INT_EN_REG, cfg->interrupt_en) != 0) {
while (dev->driver->SetReg(PIOS_MPU6000_INT_EN_REG, cfg->interrupt_en) != 0) {
;
}
// FIFO storage
while (PIOS_MPU6000_SetReg(PIOS_MPU6000_FIFO_EN_REG, cfg->Fifo_store) != 0) {
while (dev->driver->SetReg(PIOS_MPU6000_FIFO_EN_REG, cfg->Fifo_store) != 0) {
;
}
PIOS_MPU6000_ConfigureRanges(cfg->gyro_range, cfg->accel_range, cfg->filter);
// Interrupt configuration
while (PIOS_MPU6000_SetReg(PIOS_MPU6000_USER_CTRL_REG, cfg->User_ctl) != 0) {
while (dev->driver->SetReg(PIOS_MPU6000_USER_CTRL_REG, cfg->User_ctl) != 0) {
;
}
// Interrupt configuration
while (PIOS_MPU6000_SetReg(PIOS_MPU6000_PWR_MGMT_REG, cfg->Pwr_mgmt_clk) != 0) {
while (dev->driver->SetReg(PIOS_MPU6000_PWR_MGMT_REG, cfg->Pwr_mgmt_clk) != 0) {
;
}
// Interrupt configuration
while (PIOS_MPU6000_SetReg(PIOS_MPU6000_INT_CFG_REG, cfg->interrupt_cfg) != 0) {
while (dev->driver->SetReg(PIOS_MPU6000_INT_CFG_REG, cfg->interrupt_cfg) != 0) {
;
}
// Interrupt configuration
while (PIOS_MPU6000_SetReg(PIOS_MPU6000_INT_EN_REG, cfg->interrupt_en) != 0) {
while (dev->driver->SetReg(PIOS_MPU6000_INT_EN_REG, cfg->interrupt_en) != 0) {
;
}
if ((PIOS_MPU6000_GetReg(PIOS_MPU6000_INT_EN_REG)) != cfg->interrupt_en) {
if ((dev->driver->GetReg(PIOS_MPU6000_INT_EN_REG)) != cfg->interrupt_en) {
return;
}
@ -274,12 +319,12 @@ int32_t PIOS_MPU6000_ConfigureRanges(
}
// update filter settings
while (PIOS_MPU6000_SetReg(PIOS_MPU6000_DLPF_CFG_REG, filterSetting) != 0) {
while (dev->driver->SetReg(PIOS_MPU6000_DLPF_CFG_REG, filterSetting) != 0) {
;
}
// Sample rate divider, chosen upon digital filtering settings
while (PIOS_MPU6000_SetReg(PIOS_MPU6000_SMPLRT_DIV_REG,
while (dev->driver->SetReg(PIOS_MPU6000_SMPLRT_DIV_REG,
filterSetting == PIOS_MPU6000_LOWPASS_256_HZ ?
dev->cfg->Smpl_rate_div_no_dlp : dev->cfg->Smpl_rate_div_dlp) != 0) {
;
@ -288,13 +333,13 @@ int32_t PIOS_MPU6000_ConfigureRanges(
dev->filter = filterSetting;
// Gyro range
while (PIOS_MPU6000_SetReg(PIOS_MPU6000_GYRO_CFG_REG, gyroRange) != 0) {
while (dev->driver->SetReg(PIOS_MPU6000_GYRO_CFG_REG, gyroRange) != 0) {
;
}
dev->gyro_range = gyroRange;
// Set the accel range
while (PIOS_MPU6000_SetReg(PIOS_MPU6000_ACCEL_CFG_REG, accelRange) != 0) {
while (dev->driver->SetReg(PIOS_MPU6000_ACCEL_CFG_REG, accelRange) != 0) {
;
}
@ -302,6 +347,7 @@ int32_t PIOS_MPU6000_ConfigureRanges(
return 0;
}
#ifdef PIOS_INCLUDE_SPI
/**
* @brief Claim the SPI bus for the accel communications and select this chip
* @return 0 if successful, -1 for invalid device, -2 if unable to claim bus
@ -311,11 +357,11 @@ static int32_t PIOS_MPU6000_ClaimBus(bool fast_spi)
if (PIOS_MPU6000_Validate(dev) != 0) {
return -1;
}
if (PIOS_SPI_ClaimBus(dev->spi_id) != 0) {
if (PIOS_SPI_ClaimBus(dev->port_id) != 0) {
return -2;
}
PIOS_MPU6000_SetSpeed(fast_spi);
PIOS_SPI_RC_PinSet(dev->spi_id, dev->slave_num, 0);
PIOS_SPI_RC_PinSet(dev->port_id, dev->slave_num, 0);
return 0;
}
@ -323,9 +369,9 @@ static int32_t PIOS_MPU6000_ClaimBus(bool fast_spi)
static void PIOS_MPU6000_SetSpeed(const bool fast)
{
if (fast) {
PIOS_SPI_SetClockSpeed(dev->spi_id, dev->cfg->fast_prescaler);
PIOS_SPI_SetClockSpeed(dev->port_id, dev->cfg->fast_prescaler);
} else {
PIOS_SPI_SetClockSpeed(dev->spi_id, dev->cfg->std_prescaler);
PIOS_SPI_SetClockSpeed(dev->port_id, dev->cfg->std_prescaler);
}
}
@ -340,11 +386,11 @@ static int32_t PIOS_MPU6000_ClaimBusISR(bool *woken, bool fast_spi)
if (PIOS_MPU6000_Validate(dev) != 0) {
return -1;
}
if (PIOS_SPI_ClaimBusISR(dev->spi_id, woken) != 0) {
if (PIOS_SPI_ClaimBusISR(dev->port_id, woken) != 0) {
return -2;
}
PIOS_MPU6000_SetSpeed(fast_spi);
PIOS_SPI_RC_PinSet(dev->spi_id, dev->slave_num, 0);
PIOS_SPI_RC_PinSet(dev->port_id, dev->slave_num, 0);
return 0;
}
@ -357,8 +403,8 @@ static int32_t PIOS_MPU6000_ReleaseBus()
if (PIOS_MPU6000_Validate(dev) != 0) {
return -1;
}
PIOS_SPI_RC_PinSet(dev->spi_id, dev->slave_num, 1);
return PIOS_SPI_ReleaseBus(dev->spi_id);
PIOS_SPI_RC_PinSet(dev->port_id, dev->slave_num, 1);
return PIOS_SPI_ReleaseBus(dev->port_id);
}
/**
@ -372,8 +418,8 @@ static int32_t PIOS_MPU6000_ReleaseBusISR(bool *woken)
if (PIOS_MPU6000_Validate(dev) != 0) {
return -1;
}
PIOS_SPI_RC_PinSet(dev->spi_id, dev->slave_num, 1);
return PIOS_SPI_ReleaseBusISR(dev->spi_id, woken);
PIOS_SPI_RC_PinSet(dev->port_id, dev->slave_num, 1);
return PIOS_SPI_ReleaseBusISR(dev->port_id, woken);
}
/**
@ -381,7 +427,7 @@ static int32_t PIOS_MPU6000_ReleaseBusISR(bool *woken)
* @returns The register value or -1 if failure to get bus
* @param reg[in] Register address to be read
*/
static int32_t PIOS_MPU6000_GetReg(uint8_t reg)
static int32_t PIOS_MPU6000_SPI_GetReg(uint8_t reg)
{
uint8_t data;
@ -389,8 +435,8 @@ static int32_t PIOS_MPU6000_GetReg(uint8_t reg)
return -1;
}
PIOS_SPI_TransferByte(dev->spi_id, (0x80 | reg)); // request byte
data = PIOS_SPI_TransferByte(dev->spi_id, 0); // receive response
PIOS_SPI_TransferByte(dev->port_id, (0x80 | reg)); // request byte
data = PIOS_SPI_TransferByte(dev->port_id, 0); // receive response
PIOS_MPU6000_ReleaseBus();
return data;
@ -404,18 +450,18 @@ static int32_t PIOS_MPU6000_GetReg(uint8_t reg)
* \return -1 if unable to claim SPI bus
* \return -2 if unable to claim i2c device
*/
static int32_t PIOS_MPU6000_SetReg(uint8_t reg, uint8_t data)
static int32_t PIOS_MPU6000_SPI_SetReg(uint8_t reg, uint8_t data)
{
if (PIOS_MPU6000_ClaimBus(false) != 0) {
return -1;
}
if (PIOS_SPI_TransferByte(dev->spi_id, 0x7f & reg) != 0) {
if (PIOS_SPI_TransferByte(dev->port_id, 0x7f & reg) != 0) {
PIOS_MPU6000_ReleaseBus();
return -2;
}
if (PIOS_SPI_TransferByte(dev->spi_id, data) != 0) {
if (PIOS_SPI_TransferByte(dev->port_id, data) != 0) {
PIOS_MPU6000_ReleaseBus();
return -3;
}
@ -439,7 +485,7 @@ int32_t PIOS_MPU6000_DummyReadGyros()
return -1;
}
if (PIOS_SPI_TransferBlock(dev->spi_id, &buf[0], &rec[0], sizeof(buf), NULL) < 0) {
if (PIOS_SPI_TransferBlock(dev->port_id, &buf[0], &rec[0], sizeof(buf), NULL) < 0) {
return -2;
}
@ -448,13 +494,127 @@ int32_t PIOS_MPU6000_DummyReadGyros()
return 0;
}
static bool PIOS_MPU6000_SPI_ReadSensor(bool *woken)
{
const uint8_t mpu6000_send_buf[1 + PIOS_MPU6000_SAMPLES_BYTES] = { PIOS_MPU6000_SENSOR_FIRST_REG | 0x80 };
if (PIOS_MPU6000_ClaimBusISR(woken, true) != 0) {
return false;
}
if (PIOS_SPI_TransferBlock(dev->port_id, &mpu6000_send_buf[0], &mpu6000_data.buffer[0], sizeof(mpu6000_data_t), NULL) < 0) {
PIOS_MPU6000_ReleaseBusISR(woken);
return false;
}
PIOS_MPU6000_ReleaseBusISR(woken);
return true;
}
#endif /* PIOS_INCLUDE_SPI */
#ifdef PIOS_INCLUDE_I2C
static int32_t PIOS_MPU6000_I2C_SetReg(uint8_t address, uint8_t buffer)
{
uint8_t data[] = {
address,
buffer,
};
const struct pios_i2c_txn txn_list[] = {
{
.info = __func__,
.addr = dev->cfg->i2c_addr,
.rw = PIOS_I2C_TXN_WRITE,
.len = sizeof(data),
.buf = data,
}
,
};
return PIOS_I2C_Transfer(dev->port_id, txn_list, NELEMENTS(txn_list));
}
static int32_t PIOS_MPU6000_I2C_Read(uint8_t address, uint8_t *buffer, uint8_t len)
{
uint8_t addr_buffer[] = {
address,
};
const struct pios_i2c_txn txn_list[] = {
{
.info = __func__,
.addr = dev->cfg->i2c_addr,
.rw = PIOS_I2C_TXN_WRITE,
.len = sizeof(addr_buffer),
.buf = addr_buffer,
}
,
{
.info = __func__,
.addr = dev->cfg->i2c_addr,
.rw = PIOS_I2C_TXN_READ,
.len = len,
.buf = buffer,
}
};
return PIOS_I2C_Transfer(dev->port_id, txn_list, NELEMENTS(txn_list));
}
static int32_t PIOS_MPU6000_I2C_GetReg(uint8_t address)
{
uint8_t data;
if (PIOS_MPU6000_I2C_Read(address, &data, sizeof(data)) < 0) {
return -1;
}
return data;
}
static bool PIOS_MPU6000_I2C_Read_Completed()
{
return PIOS_MPU6000_HandleData(gyro_read_timestamp);
}
static bool PIOS_MPU6000_I2C_ReadSensor(bool *woken)
{
static uint8_t addr_buffer[] = {
PIOS_MPU6000_SENSOR_FIRST_REG,
};
static struct pios_i2c_txn txn_list[] = {
{
.info = __func__,
// .addr = dev->cfg->i2c_addr,
.rw = PIOS_I2C_TXN_WRITE,
.len = sizeof(addr_buffer),
.buf = addr_buffer,
}
,
{
.info = __func__,
// .addr = dev->cfg->i2c_addr,
.rw = PIOS_I2C_TXN_READ,
.len = sizeof(mpu6000_data_t) - 1,
.buf = &mpu6000_data.buffer[1],
}
};
txn_list[0].addr = dev->cfg->i2c_addr;
txn_list[1].addr = dev->cfg->i2c_addr;
PIOS_I2C_Transfer_CallbackFromISR(dev->port_id, txn_list, NELEMENTS(txn_list), PIOS_MPU6000_I2C_Read_Completed, woken);
return false; /* we did not read anything now */
}
#endif /* PIOS_INCLUDE_I2C */
/*
* @brief Read the identification bytes from the MPU6000 sensor
* \return ID read from MPU6000 or -1 if failure
*/
int32_t PIOS_MPU6000_ReadID()
{
int32_t mpu6000_id = PIOS_MPU6000_GetReg(PIOS_MPU6000_WHOAMI);
int32_t mpu6000_id = dev->driver->GetReg(PIOS_MPU6000_WHOAMI);
if (mpu6000_id < 0) {
return -1;
@ -541,21 +701,21 @@ static int32_t PIOS_MPU6000_Test(void)
bool PIOS_MPU6000_IRQHandler(void)
{
uint32_t gyro_read_timestamp = PIOS_DELAY_GetRaw();
gyro_read_timestamp = PIOS_DELAY_GetRaw();
bool woken = false;
if (!mpu6000_configured) {
return false;
}
if (PIOS_MPU6000_ReadSensor(&woken)) {
if (dev->driver->ReadSensor(&woken)) {
woken |= PIOS_MPU6000_HandleData(gyro_read_timestamp);
}
return woken;
}
static bool PIOS_MPU6000_HandleData(uint32_t gyro_read_timestamp)
static bool PIOS_MPU6000_HandleData(uint32_t gyro_read_timestamp_p)
{
if (!queue_data) {
return false;
@ -564,8 +724,6 @@ static bool PIOS_MPU6000_HandleData(uint32_t gyro_read_timestamp)
// Rotate the sensor to OP convention. The datasheet defines X as towards the right
// and Y as forward. OP convention transposes this. Also the Z is defined negatively
// to our convention
// Currently we only support rotations on top so switch X/Y accordingly
switch (dev->cfg->orientation) {
case PIOS_MPU6000_TOP_0DEG:
queue_data->sample[0].y = GET_SENSOR_DATA(mpu6000_data, Accel_X); // chip X
@ -592,34 +750,49 @@ static bool PIOS_MPU6000_HandleData(uint32_t gyro_read_timestamp)
queue_data->sample[1].y = GET_SENSOR_DATA(mpu6000_data, Gyro_Y); // chip Y
queue_data->sample[1].x = -1 - (GET_SENSOR_DATA(mpu6000_data, Gyro_X)); // chip X
break;
case PIOS_MPU6000_BOTTOM_0DEG:
queue_data->sample[0].y = GET_SENSOR_DATA(mpu6000_data, Accel_X); // chip X
queue_data->sample[0].x = -1 - GET_SENSOR_DATA(mpu6000_data, Accel_Y); // chip Y
queue_data->sample[1].y = GET_SENSOR_DATA(mpu6000_data, Gyro_X); // chip X
queue_data->sample[1].x = -1 - GET_SENSOR_DATA(mpu6000_data, Gyro_Y); // chip Y
break;
case PIOS_MPU6000_BOTTOM_90DEG:
queue_data->sample[0].y = GET_SENSOR_DATA(mpu6000_data, Accel_Y); // chip Y
queue_data->sample[0].x = GET_SENSOR_DATA(mpu6000_data, Accel_X); // chip X
queue_data->sample[1].y = GET_SENSOR_DATA(mpu6000_data, Gyro_Y); // chip Y
queue_data->sample[1].x = GET_SENSOR_DATA(mpu6000_data, Gyro_X); // chip X
break;
case PIOS_MPU6000_BOTTOM_180DEG:
queue_data->sample[0].y = -1 - (GET_SENSOR_DATA(mpu6000_data, Accel_X)); // chip X
queue_data->sample[0].x = GET_SENSOR_DATA(mpu6000_data, Accel_Y); // chip Y
queue_data->sample[1].y = -1 - (GET_SENSOR_DATA(mpu6000_data, Gyro_X)); // chip X
queue_data->sample[1].x = GET_SENSOR_DATA(mpu6000_data, Gyro_Y); // chip Y
break;
case PIOS_MPU6000_BOTTOM_270DEG:
queue_data->sample[0].y = -1 - (GET_SENSOR_DATA(mpu6000_data, Accel_Y)); // chip Y
queue_data->sample[0].x = -1 - (GET_SENSOR_DATA(mpu6000_data, Accel_X)); // chip X
queue_data->sample[1].y = -1 - (GET_SENSOR_DATA(mpu6000_data, Gyro_Y)); // chip Y
queue_data->sample[1].x = -1 - (GET_SENSOR_DATA(mpu6000_data, Gyro_X)); // chip X
break;
}
if ((dev->cfg->orientation & PIOS_MPU6000_LOCATION_MASK) == PIOS_MPU6000_LOCATION_TOP) {
queue_data->sample[0].z = -1 - (GET_SENSOR_DATA(mpu6000_data, Accel_Z));
queue_data->sample[1].z = -1 - (GET_SENSOR_DATA(mpu6000_data, Gyro_Z));
} else {
queue_data->sample[0].z = GET_SENSOR_DATA(mpu6000_data, Accel_Z);
queue_data->sample[1].z = GET_SENSOR_DATA(mpu6000_data, Gyro_Z);
}
const int16_t temp = GET_SENSOR_DATA(mpu6000_data, Temperature);
// Temperature in degrees C = (TEMP_OUT Register Value as a signed quantity)/340 + 36.53
queue_data->temperature = 3653 + (temp * 100) / 340;
queue_data->timestamp = gyro_read_timestamp;
queue_data->timestamp = gyro_read_timestamp_p;
BaseType_t higherPriorityTaskWoken;
xQueueSendToBackFromISR(dev->queue, (void *)queue_data, &higherPriorityTaskWoken);
return higherPriorityTaskWoken == pdTRUE;
}
static bool PIOS_MPU6000_ReadSensor(bool *woken)
{
const uint8_t mpu6000_send_buf[1 + PIOS_MPU6000_SAMPLES_BYTES] = { PIOS_MPU6000_SENSOR_FIRST_REG | 0x80 };
if (PIOS_MPU6000_ClaimBusISR(woken, true) != 0) {
return false;
}
if (PIOS_SPI_TransferBlock(dev->spi_id, &mpu6000_send_buf[0], &mpu6000_data.buffer[0], sizeof(mpu6000_data_t), NULL) < 0) {
PIOS_MPU6000_ReleaseBusISR(woken);
return false;
}
PIOS_MPU6000_ReleaseBusISR(woken);
return true;
}
// Sensor driver implementation
bool PIOS_MPU6000_driver_Test(__attribute__((unused)) uintptr_t context)
{
@ -628,7 +801,7 @@ bool PIOS_MPU6000_driver_Test(__attribute__((unused)) uintptr_t context)
void PIOS_MPU6000_driver_Reset(__attribute__((unused)) uintptr_t context)
{
PIOS_MPU6000_DummyReadGyros();
// PIOS_MPU6000_DummyReadGyros();
}
void PIOS_MPU6000_driver_get_scale(float *scales, uint8_t size, __attribute__((unused)) uintptr_t contet)

View File

@ -129,6 +129,7 @@ static volatile bool mag_ready = false;
static struct mpu9250_dev *dev;
volatile bool mpu9250_configured = false;
static mpu9250_data_t mpu9250_data;
static int32_t mpu9250_id;
// ! Private functions
static struct mpu9250_dev *PIOS_MPU9250_alloc(const struct pios_mpu9250_cfg *cfg);
@ -186,8 +187,10 @@ void PIOS_MPU9250_MainRegister()
void PIOS_MPU9250_MagRegister()
{
if (mpu9250_id == PIOS_MPU9250_GYRO_ACC_ID) {
PIOS_SENSORS_Register(&PIOS_MPU9250_Mag_Driver, PIOS_SENSORS_TYPE_3AXIS_MAG, 0);
}
}
/**
* @brief Allocate a new device
*/
@ -320,7 +323,9 @@ static void PIOS_MPU9250_Config(struct pios_mpu9250_cfg const *cfg)
}
#ifdef PIOS_MPU9250_MAG
if (mpu9250_id == PIOS_MPU9250_GYRO_ACC_ID) {
PIOS_MPU9250_Mag_Init();
}
#endif
// Interrupt enable
@ -514,12 +519,12 @@ static int32_t PIOS_MPU9250_SetReg(uint8_t reg, uint8_t data)
*/
int32_t PIOS_MPU9250_ReadID()
{
int32_t mpu9250_id = PIOS_MPU9250_GetReg(PIOS_MPU9250_WHOAMI);
int32_t id = PIOS_MPU9250_GetReg(PIOS_MPU9250_WHOAMI);
if (mpu9250_id < 0) {
if (id < 0) {
return -1;
}
return mpu9250_id;
return id;
}
static float PIOS_MPU9250_GetScale()
@ -566,13 +571,13 @@ static float PIOS_MPU9250_GetAccelScale()
static int32_t PIOS_MPU9250_Test(void)
{
/* Verify that ID matches */
int32_t mpu9250_id = PIOS_MPU9250_ReadID();
mpu9250_id = PIOS_MPU9250_ReadID();
if (mpu9250_id < 0) {
return -1;
}
if (mpu9250_id != PIOS_MPU9250_GYRO_ACC_ID) {
if ((mpu9250_id != PIOS_MPU9250_GYRO_ACC_ID) && (mpu9250_id != PIOS_MPU6500_GYRO_ACC_ID)) {
return -2;
}

View File

@ -82,7 +82,6 @@ struct pios_sbus_state {
struct pios_sbus_dev {
enum pios_sbus_dev_magic magic;
const struct pios_sbus_cfg *cfg;
struct pios_sbus_state state;
};
@ -153,7 +152,6 @@ int32_t PIOS_SBus_Init(uint32_t *sbus_id,
uint32_t lower_id)
{
PIOS_DEBUG_Assert(sbus_id);
PIOS_DEBUG_Assert(cfg);
PIOS_DEBUG_Assert(driver);
struct pios_sbus_dev *sbus_dev;
@ -163,9 +161,6 @@ int32_t PIOS_SBus_Init(uint32_t *sbus_id,
goto out_fail;
}
/* Bind the configuration to the device instance */
sbus_dev->cfg = cfg;
PIOS_SBus_ResetState(&(sbus_dev->state));
*sbus_id = (uint32_t)sbus_dev;

View File

@ -100,7 +100,7 @@ extern void PIOS_Servo_Disable()
GPIO_InitTypeDef init = chan->pin.init;
#if defined(STM32F40_41xxx) || defined(STM32F446xx) || defined(STM32F411xE)
#if defined(STM32F40_41xxx) || defined(STM32F446xx) || defined(STM32F411xE) || defined(STM32F3)
init.GPIO_Mode = GPIO_Mode_OUT;
#elif defined(STM32F10X_MD)
init.GPIO_Mode = GPIO_Mode_Out_PP;
@ -147,7 +147,7 @@ static void PIOS_Servo_SetupBank(uint8_t bank_nr)
switch (bank->mode) {
case PIOS_SERVO_BANK_MODE_PWM:
case PIOS_SERVO_BANK_MODE_SINGLE_PULSE:
#if defined(STM32F40_41xxx) || defined(STM32F446xx) || defined(STM32F411xE)
#if defined(STM32F40_41xxx) || defined(STM32F446xx) || defined(STM32F411xE) || defined(STM32F3)
GPIO_PinAFConfig(chan->pin.gpio, chan->pin.pin_source, chan->remap);
#elif defined(STM32F10X_MD)
init.GPIO_Mode = GPIO_Mode_AF_PP;
@ -162,28 +162,27 @@ static void PIOS_Servo_SetupBank(uint8_t bank_nr)
/* Set up for output compare function */
switch (chan->timer_chan) {
case TIM_Channel_1:
TIM_OC1Init(chan->timer, &servo_cfg->tim_oc_init);
TIM_OC1Init(chan->timer, (TIM_OCInitTypeDef *)&servo_cfg->tim_oc_init);
TIM_OC1PreloadConfig(chan->timer, TIM_OCPreload_Enable);
break;
case TIM_Channel_2:
TIM_OC2Init(chan->timer, &servo_cfg->tim_oc_init);
TIM_OC2Init(chan->timer, (TIM_OCInitTypeDef *)&servo_cfg->tim_oc_init);
TIM_OC2PreloadConfig(chan->timer, TIM_OCPreload_Enable);
break;
case TIM_Channel_3:
TIM_OC3Init(chan->timer, &servo_cfg->tim_oc_init);
TIM_OC3Init(chan->timer, (TIM_OCInitTypeDef *)&servo_cfg->tim_oc_init);
TIM_OC3PreloadConfig(chan->timer, TIM_OCPreload_Enable);
break;
case TIM_Channel_4:
TIM_OC4Init(chan->timer, &servo_cfg->tim_oc_init);
TIM_OC4Init(chan->timer, (TIM_OCInitTypeDef *)&servo_cfg->tim_oc_init);
TIM_OC4PreloadConfig(chan->timer, TIM_OCPreload_Enable);
break;
}
break;
case PIOS_SERVO_BANK_MODE_DSHOT:
{
#if defined(STM32F40_41xxx) || defined(STM32F446xx) || defined(STM32F411xE)
#if defined(STM32F40_41xxx) || defined(STM32F446xx) || defined(STM32F411xE) || defined(STM32F3)
init.GPIO_Mode = GPIO_Mode_OUT;
#elif defined(STM32F10X_MD)
init.GPIO_Mode = GPIO_Mode_Out_PP;
@ -504,8 +503,8 @@ void PIOS_Servo_SetHz(const uint16_t *speeds, const uint32_t *clock, uint8_t ban
// Choose the correct prescaler value for the APB the timer is attached
#if defined(STM32F10X_MD)
// F1 has both timer clock domains running at master clock speed
#if defined(STM32F10X_MD) || defined(STM32F3)
// F1 & F3 have both timer clock domains running at master clock speed
timer_clock = PIOS_MASTER_CLOCK;
#elif defined(STM32F40_41xxx) || defined(STM32F446xx) || defined(STM32F411xE)
if (timer == TIM1 || timer == TIM8 || timer == TIM9 || timer == TIM10 || timer == TIM11) {

View File

@ -0,0 +1,61 @@
/**
******************************************************************************
* @addtogroup PIOS PIOS Core hardware abstraction layer
* @{
* @addtogroup PIOS_BMP280 BMP280 Functions
* @brief Hardware functions to deal with the altitude pressure sensor
* @{
*
* @file pios_bmp280.h
* @author The LibrePilot Team, http://www.librepilot.org Copyright (C) 2017.
* @brief BMP280 functions header.
* @see The GNU Public License (GPL) Version 3
*
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef PIOS_BMP280_H
#define PIOS_BMP280_H
#include <pios_sensors.h>
#define BMP280_OVERSAMP_SKIPPED (0x00)
#define BMP280_OVERSAMP_1X (0x01)
#define BMP280_OVERSAMP_2X (0x02)
#define BMP280_OVERSAMP_4X (0x03)
#define BMP280_OVERSAMP_8X (0x04)
#define BMP280_OVERSAMP_16X (0x05)
#define BMP280_PRESSURE_OSR(x) (x << 2)
#define BMP280_TEMPERATURE_OSR(x) (x << 5)
#define BMP280_STANDARD_RESOLUTION (BMP280_PRESSURE_OSR(BMP280_OVERSAMP_4X) | BMP280_TEMPERATURE_OSR(BMP280_OVERSAMP_1X))
#define BMP280_HIGH_RESOLUTION (BMP280_PRESSURE_OSR(BMP280_OVERSAMP_8X) | BMP280_TEMPERATURE_OSR(BMP280_OVERSAMP_1X))
#define BMP280_ULTRA_HIGH_RESOLUTION (BMP280_PRESSURE_OSR(BMP280_OVERSAMP_16X) | BMP280_TEMPERATURE_OSR(BMP280_OVERSAMP_2X))
struct pios_bmp280_cfg {
uint8_t oversampling;
};
/* Public Functions */
extern void PIOS_BMP280_Init(const struct pios_bmp280_cfg *cfg, uint32_t i2c_device);
#endif /* PIOS_BMP280_H */
/**
* @}
* @}
*/

View File

@ -68,4 +68,7 @@ const struct pios_l3gd20_cfg *PIOS_BOARD_HW_DEFS_GetL3GD20Cfg(uint32_t board_rev
#ifdef PIOS_INCLUDE_BMA180
const struct pios_bma180_cfg *PIOS_BOARD_HW_DEFS_GetBMA180Cfg(uint32_t board_revision);
#endif
#ifdef PIOS_INCLUDE_BMP280
const struct pios_bmp280_cfg *PIOS_BOARD_HW_DEFS_GetBMP280Cfg(uint32_t board_revision);
#endif
#endif /* PIOS_BOARD_HW_H */

View File

@ -172,9 +172,6 @@ extern uint32_t pios_com_frsky_sensorhub_id;
#ifndef PIOS_COM_FRSKY_SENSORHUB_TX_BUF_LEN
# define PIOS_COM_FRSKY_SENSORHUB_TX_BUF_LEN 128
#endif
#ifndef PIOS_COM_FRSKY_SENSORHUB_RX_BUF_LEN
# define PIOS_COM_FRSKY_SENSORHUB_RX_BUF_LEN 128
#endif
/* USB VCP */
extern uint32_t pios_com_vcp_id;
@ -207,7 +204,9 @@ typedef enum {
PIOS_BOARD_IO_UART_COMBRIDGE, /* com */
PIOS_BOARD_IO_UART_DEBUGCONSOLE, /* com */
PIOS_BOARD_IO_UART_OSDHK, /* com */
PIOS_BOARD_IO_UART_SBUS, /* rcvr */
PIOS_BOARD_IO_UART_SBUS, /* rcvr, normal vs not-inverted from HwSettings.SBusMode */
PIOS_BOARD_IO_UART_SBUS_NORMAL, /* helper only */
PIOS_BOARD_IO_UART_SBUS_NOT_INVERTED, /* helper only */
PIOS_BOARD_IO_UART_DSM_MAIN, /* rcvr */
PIOS_BOARD_IO_UART_DSM_FLEXI, /* rcvr */
PIOS_BOARD_IO_UART_DSM_RCVR, /* rcvr */

View File

@ -62,13 +62,6 @@ enum PIOS_COM_Parity {
PIOS_COM_Parity_Odd,
};
enum PIOS_COM_Mode {
PIOS_COM_Mode_Unchanged = 0,
PIOS_COM_Mode_Rx = (1 << 0),
PIOS_COM_Mode_Tx = (1 << 1),
PIOS_COM_Mode_RxTx = (PIOS_COM_Mode_Rx | PIOS_COM_Mode_Tx),
};
struct pios_com_driver {
void (*set_baud)(uint32_t id, uint32_t baud);
void (*set_config)(uint32_t usart_id, enum PIOS_COM_Word_Length word_len, enum PIOS_COM_Parity parity, enum PIOS_COM_StopBits stop_bits, uint32_t baud_rate);

View File

@ -32,13 +32,17 @@
#define PIOS_DEBUG_H
#ifdef PIOS_INCLUDE_DEBUG_CONSOLE
# ifndef PIOS_COM_DEBUG
extern uint32_t pios_com_debug_id;
# define PIOS_COM_DEBUG (pios_com_debug_id)
# endif
# ifndef DEBUG_LEVEL
# define DEBUG_LEVEL 0
# endif
# define DEBUG_PRINTF(level, ...) \
{ \
if ((level <= DEBUG_LEVEL) && (PIOS_COM_DEBUG > 0)) { \
PIOS_COM_SendFormattedStringNonBlocking(PIOS_COM_DEBUG, __VA_ARGS__); \
PIOS_COM_SendFormattedString(PIOS_COM_DEBUG, __VA_ARGS__); \
} \
}
#else

View File

@ -32,7 +32,9 @@
#ifndef PIOS_DELAY_H
#define PIOS_DELAY_H
#ifndef USE_SIM_POSIX
#ifdef USE_SIM_POSIX
extern uint32_t PIOS_DELAY_GetRaw();
#else
#include "pios_delay_raw.h"
#endif

View File

@ -72,6 +72,15 @@ const struct pios_flash_jedec_cfg pios_flash_jedec_catalog[] =
.fast_read = 0x0B,
.fast_read_dummy_bytes = 1,
},
{ // 25q64
.expect_manufacturer = JEDEC_MANUFACTURER_WINBOND,
.expect_memorytype = 0x40,
.expect_capacity = 0x17,
.sector_erase = 0x20,
.chip_erase = 0x60,
.fast_read = 0x0B,
.fast_read_dummy_bytes = 1,
},
{ // 25q512
.expect_manufacturer = JEDEC_MANUFACTURER_MICRON,
.expect_memorytype = 0xBA,

View File

@ -37,6 +37,23 @@
#define NELEMENTS(x) (sizeof(x) / sizeof((x)[0]))
/**
* @brief preprocessor magic
*
*/
#define _CONCAT5(a, b, c, d, e) a##b##c##d##e
#define _EVAL5(a, b, c, d, e) _CONCAT5(a, b, c, d, e)
#define _CONCAT4(a, b, c, d) a##b##c##d
#define _EVAL4(a, b, c, d) _CONCAT4(a, b, c, d)
#define _CONCAT3(a, b, c) a##b##c
#define _EVAL3(a, b, c) _CONCAT3(a, b, c)
#define _CONCAT2(a, b) a##b
#define _EVAL2(a, b) _CONCAT4(a, b)
/**
* @brief Compiler barrier: Disables compiler load/store reordering across the barrier
*

View File

@ -73,9 +73,13 @@ enum pios_i2c_error_count {
PIOS_I2C_ERROR_COUNT_NUMELEM,
};
typedef bool (*pios_i2c_callback)();
/* Public Functions */
extern int32_t PIOS_I2C_Transfer(uint32_t i2c_id, const struct pios_i2c_txn txn_list[], uint32_t num_txns);
extern int32_t PIOS_I2C_Transfer_Callback(uint32_t i2c_id, const struct pios_i2c_txn txn_list[], uint32_t num_txns, void *callback);
extern int32_t PIOS_I2C_Transfer_Callback(uint32_t i2c_id, const struct pios_i2c_txn txn_list[], uint32_t num_txns, pios_i2c_callback callback);
extern int32_t PIOS_I2C_Transfer_CallbackFromISR(uint32_t i2c_id, const struct pios_i2c_txn txn_list[], uint32_t num_txns, pios_i2c_callback callback, bool *woken);
extern void PIOS_I2C_EV_IRQ_Handler(uint32_t i2c_id);
extern void PIOS_I2C_ER_IRQ_Handler(uint32_t i2c_id);
extern void PIOS_I2C_IRQ_Handler(uint32_t i2c_id);

View File

@ -69,7 +69,7 @@ struct pios_i2c_adapter {
const struct pios_i2c_txn *active_txn;
const struct pios_i2c_txn *last_txn;
void (*callback)();
pios_i2c_callback callback;
uint8_t *active_byte;
uint8_t *last_byte;

View File

@ -125,15 +125,27 @@ enum pios_mpu6000_accel_range {
PIOS_MPU6000_ACCEL_16G = 0x18
};
enum pios_mpu6000_orientation { // clockwise rotation from board forward
PIOS_MPU6000_TOP_0DEG = 0x00,
PIOS_MPU6000_TOP_90DEG = 0x01,
PIOS_MPU6000_TOP_180DEG = 0x02,
PIOS_MPU6000_TOP_270DEG = 0x03
#define PIOS_MPU6000_LOCATION_TOP 0x00
#define PIOS_MPU6000_LOCATION_BOTTOM 0x10
#define PIOS_MPU6000_LOCATION_MASK 0xf0
enum pios_mpu6000_orientation { // clockwise rotation from board forward, when looking at sensor itself, which can be also on the bottom side
PIOS_MPU6000_TOP_0DEG = 0 | PIOS_MPU6000_LOCATION_TOP,
PIOS_MPU6000_TOP_90DEG = 1 | PIOS_MPU6000_LOCATION_TOP,
PIOS_MPU6000_TOP_180DEG = 2 | PIOS_MPU6000_LOCATION_TOP,
PIOS_MPU6000_TOP_270DEG = 3 | PIOS_MPU6000_LOCATION_TOP,
PIOS_MPU6000_BOTTOM_0DEG = 4 | PIOS_MPU6000_LOCATION_BOTTOM,
PIOS_MPU6000_BOTTOM_90DEG = 5 | PIOS_MPU6000_LOCATION_BOTTOM,
PIOS_MPU6000_BOTTOM_180DEG = 6 | PIOS_MPU6000_LOCATION_BOTTOM,
PIOS_MPU6000_BOTTOM_270DEG = 7 | PIOS_MPU6000_LOCATION_BOTTOM,
};
struct pios_mpu6000_cfg {
const struct pios_exti_cfg *exti_cfg; /* Pointer to the EXTI configuration */
uint8_t i2c_addr;
uint8_t Fifo_store; /* FIFO storage of different readings (See datasheet page 31 for more details) */
@ -148,13 +160,15 @@ struct pios_mpu6000_cfg {
enum pios_mpu6000_range gyro_range;
enum pios_mpu6000_filter filter;
enum pios_mpu6000_orientation orientation;
#ifdef PIOS_INCLUDE_SPI
SPIPrescalerTypeDef fast_prescaler;
SPIPrescalerTypeDef std_prescaler;
#endif /* PIOS_INCLUDE_SPI */
uint8_t max_downsample;
};
/* Public Functions */
extern int32_t PIOS_MPU6000_Init(uint32_t spi_id, uint32_t slave_num, const struct pios_mpu6000_cfg *new_cfg);
extern int32_t PIOS_MPU6000_Init(uint32_t port_id, uint32_t slave_num, const struct pios_mpu6000_cfg *new_cfg);
extern int32_t PIOS_MPU6000_ConfigureRanges(enum pios_mpu6000_range gyroRange, enum pios_mpu6000_accel_range accelRange, enum pios_mpu6000_filter filterSetting);
extern int32_t PIOS_MPU6000_ReadID();
extern void PIOS_MPU6000_Register();

View File

@ -33,6 +33,8 @@
#define PIOS_MPU9250_H
#include <pios_sensors.h>
#ifdef PIOS_INCLUDE_MPU9250
/* MPU9250 Addresses */
#define PIOS_MPU9250_SMPLRT_DIV_REG 0X19
#define PIOS_MPU9250_DLPF_CFG_REG 0X1A
@ -153,6 +155,7 @@
#define PIOS_MPU9250_ASAZ 0X12
/* IDs */
#define PIOS_MPU6500_GYRO_ACC_ID 0x70
#define PIOS_MPU9250_GYRO_ACC_ID 0x71
#define PIOS_MPU9250_MAG_ID 0x48
@ -246,6 +249,8 @@ extern bool PIOS_MPU9250_IRQHandler(void);
extern const PIOS_SENSORS_Driver PIOS_MPU9250_Main_Driver;
extern const PIOS_SENSORS_Driver PIOS_MPU9250_Mag_Driver;
#endif /* PIOS_INCLUDE_MPU9250 */
#endif /* PIOS_MPU9250_H */
/**

View File

@ -85,11 +85,6 @@
*/
struct pios_sbus_cfg {
bool non_inverted;
// struct stm32_gpio inv;
// void (*gpio_clk_func)(uint32_t periph, FunctionalState state);
// uint32_t gpio_clk_periph;
// BitAction gpio_inv_enable;
// BitAction gpio_inv_disable;
};
extern const struct pios_rcvr_driver pios_sbus_rcvr_driver;

View File

@ -55,6 +55,7 @@ enum PIOS_USART_Inverted {
#define PIOS_IOCTL_USART_GET_DSMBIND COM_IOCTL(COM_IOCTL_TYPE_USART, 7, struct stm32_gpio)
#define PIOS_IOCTL_USART_LOCK_CONFIG COM_IOCTL(COM_IOCTL_TYPE_USART, 8, bool)
#endif /* PIOS_USART_H */

View File

@ -363,7 +363,7 @@ enum usb_product_ids {
USB_PRODUCT_ID_REVOLUTION = 0x415E,
USB_PRODUCT_ID_SPARKY2 = 0x41D0, // was 0x415E during LP testing
USB_PRODUCT_ID_OSD = 0x4194,
USB_PRODUCT_ID_SPARE = 0x4195,
USB_PRODUCT_ID_LIBREPILOT = 0x4195,
} __attribute__((packed));
enum usb_op_board_ids {
@ -374,6 +374,12 @@ enum usb_op_board_ids {
USB_OP_BOARD_ID_REVOLUTION = 5,
USB_OP_BOARD_ID_SPARKY2 = 5,
USB_OP_BOARD_ID_OSD = 6,
USB_OP_BOARD_ID_CCF3D = 7,
USB_OP_BOARD_ID_SPRACINGF3 = 8,
USB_OP_BOARD_ID_SPRACINGF3EVO = 9,
USB_OP_BOARD_ID_NUCLEOF303RE = 10,
USB_OP_BOARD_ID_PIKOBLX = 11,
USB_OP_BOARD_ID_TINYFISH = 12,
} __attribute__((packed));
enum usb_op_board_modes {

View File

@ -64,6 +64,8 @@ extern "C" {
#include <stm32f4xx_rcc.h>
#elif defined(STM32F0)
#include <stm32f0xx.h>
#elif defined(STM32F3)
#include <stm32f30x.h>
#else
#error "No Architecture defined"
#endif

View File

@ -124,12 +124,17 @@ int32_t PIOS_SYS_Reset(void)
PIOS_IRQ_Disable();
// turn off all board LEDs
#if defined(PIOS_LED_HEARTBEAT)
#ifdef PIOS_INCLUDE_LED
# ifdef PIOS_LED_HEARTBEAT
PIOS_LED_Off(PIOS_LED_HEARTBEAT);
# endif /* PIOS_LED_HEARTBEAT */
#if defined(PIOS_LED_ALARM)
# ifdef PIOS_LED_ALARM
PIOS_LED_Off(PIOS_LED_ALARM);
# endif /* PIOS_LED_ALARM */
# ifdef PIOS_BUZZER_ALARM
PIOS_LED_Off(PIOS_BUZZER_ALARM);
# endif /* PIOS_BUZZER_ALARM */
#endif /* PIOS_INCLUDE_LED */
/* Reset STM32 */
NVIC_SystemReset();

View File

@ -173,6 +173,32 @@ int32_t PIOS_USART_Init(uint32_t *usart_id, const struct pios_usart_cfg *cfg)
PIOS_DEBUG_Assert(usart_id);
PIOS_DEBUG_Assert(cfg);
uint32_t *local_id;
uint8_t irq_channel;
/* Enable USART clock */
switch ((uint32_t)cfg->regs) {
case (uint32_t)USART1:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
local_id = &PIOS_USART_1_id;
irq_channel = USART1_IRQn;
break;
case (uint32_t)USART2:
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
local_id = &PIOS_USART_2_id;
irq_channel = USART2_IRQn;
break;
#if defined(STM32F072)
case (uint32_t)USART3:
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
local_id = &PIOS_USART_3_id;
irq_channel = USART3_4_IRQn;
break;
#endif
default:
goto out_fail;
}
struct pios_usart_dev *usart_dev;
usart_dev = (struct pios_usart_dev *)PIOS_USART_alloc();
@ -182,6 +208,7 @@ int32_t PIOS_USART_Init(uint32_t *usart_id, const struct pios_usart_cfg *cfg)
/* Bind the configuration to the device instance */
usart_dev->cfg = cfg;
usart_dev->irq_channel = irq_channel;
/* Initialize the comm parameter structure */
USART_StructInit(&usart_dev->init); // 9600 8n1
@ -189,28 +216,8 @@ int32_t PIOS_USART_Init(uint32_t *usart_id, const struct pios_usart_cfg *cfg)
/* We will set modes later, depending on installed callbacks */
usart_dev->init.USART_Mode = 0;
/* Enable USART clock */
switch ((uint32_t)cfg->regs) {
case (uint32_t)USART1:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
PIOS_USART_1_id = (uint32_t)usart_dev;
usart_dev->irq_channel = USART1_IRQn;
break;
case (uint32_t)USART2:
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
PIOS_USART_2_id = (uint32_t)usart_dev;
usart_dev->irq_channel = USART2_IRQn;
break;
#if defined(STM32F072)
case (uint32_t)USART3:
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
PIOS_USART_3_id = (uint32_t)usart_dev;
usart_dev->irq_channel = USART3_4_IRQn;
break;
#endif
}
*usart_id = (uint32_t)usart_dev;
*local_id = (uint32_t)usart_dev;
PIOS_USART_SetIrqPrio(usart_dev, PIOS_IRQ_PRIO_MID);
@ -218,6 +225,9 @@ int32_t PIOS_USART_Init(uint32_t *usart_id, const struct pios_usart_cfg *cfg)
USART_OverrunDetectionConfig(usart_dev->cfg->regs, USART_OVRDetection_Disable);
return 0;
out_fail:
return -1;
}
static void PIOS_USART_Setup(struct pios_usart_dev *usart_dev)
@ -247,7 +257,15 @@ static void PIOS_USART_Setup(struct pios_usart_dev *usart_dev)
}
/* Write new configuration */
USART_Init(usart_dev->cfg->regs, &usart_dev->init);
{ // fix parity stuff
USART_InitTypeDef init = usart_dev->init;
if ((init.USART_Parity != USART_Parity_No) && (init.USART_WordLength == USART_WordLength_8b)) {
init.USART_WordLength = USART_WordLength_9b;
}
USART_Init(usart_dev->cfg->regs, &init);
}
/*
* Re enable USART.
@ -289,8 +307,6 @@ static void PIOS_USART_ChangeBaud(uint32_t usart_id, uint32_t baud)
* \param[in] word_len Requested word length
* \param[in] stop_bits Requested stop bits
* \param[in] parity Requested parity
* \param[in] baud_rate Requested baud rate
* \param[in] mode Requested mode
*
*/
static void PIOS_USART_ChangeConfig(uint32_t usart_id,

View File

@ -9,7 +9,7 @@ PIOS_DEVLIB := $(dir $(lastword $(MAKEFILE_LIST)))
LINKER_SCRIPTS_PATH = $(PIOS_DEVLIB)
# Compiler options implied by the F10x
CDEFS += -DSTM32F10X -DSTM32F10X_$(MODEL)
CDEFS += -DSTM32F10X -DSTM32F10X_$(MODEL) -DSTM32F1
CDEFS += -DUSE_STDPERIPH_DRIVER
CDEFS += -DARM_MATH_CM3
CDEFS += -DHSE_VALUE=$(OSCILLATOR_FREQ)

View File

@ -97,12 +97,17 @@ int32_t PIOS_SYS_Reset(void)
PIOS_IRQ_Disable();
// turn off all board LEDs
#if defined(PIOS_LED_HEARTBEAT)
#ifdef PIOS_INCLUDE_LED
# ifdef PIOS_LED_HEARTBEAT
PIOS_LED_Off(PIOS_LED_HEARTBEAT);
# endif /* PIOS_LED_HEARTBEAT */
#if defined(PIOS_LED_ALARM)
# ifdef PIOS_LED_ALARM
PIOS_LED_Off(PIOS_LED_ALARM);
# endif /* PIOS_LED_ALARM */
# ifdef PIOS_BUZZER_ALARM
PIOS_LED_Off(PIOS_BUZZER_ALARM);
# endif /* PIOS_BUZZER_ALARM */
#endif /* PIOS_INCLUDE_LED */
RCC_APB2PeriphResetCmd(0xffffffff, DISABLE);
RCC_APB1PeriphResetCmd(0xffffffff, DISABLE);

View File

@ -67,7 +67,7 @@ struct pios_usart_dev {
uint32_t rx_in_context;
pios_com_callback tx_out_cb;
uint32_t tx_out_context;
bool config_locked;
uint32_t rx_dropped;
uint8_t irq_channel;
};
@ -172,6 +172,35 @@ int32_t PIOS_USART_Init(uint32_t *usart_id, const struct pios_usart_cfg *cfg)
PIOS_DEBUG_Assert(usart_id);
PIOS_DEBUG_Assert(cfg);
uint32_t *local_id;
uint8_t irq_channel;
switch ((uint32_t)cfg->regs) {
case (uint32_t)USART1:
local_id = &PIOS_USART_1_id;
irq_channel = USART1_IRQn;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
break;
case (uint32_t)USART2:
local_id = &PIOS_USART_2_id;
irq_channel = USART2_IRQn;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
break;
case (uint32_t)USART3:
local_id = &PIOS_USART_3_id;
irq_channel = USART3_IRQn;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
break;
default:
goto out_fail;
}
if (*local_id) {
/* this port is already open */
*usart_id = *local_id;
return 0;
}
struct pios_usart_dev *usart_dev;
usart_dev = (struct pios_usart_dev *)PIOS_USART_alloc();
@ -181,6 +210,7 @@ int32_t PIOS_USART_Init(uint32_t *usart_id, const struct pios_usart_cfg *cfg)
/* Bind the configuration to the device instance */
usart_dev->cfg = cfg;
usart_dev->irq_channel = irq_channel;
/* Initialize the comm parameter structure */
USART_StructInit(&usart_dev->init); // 9600 8n1
@ -206,29 +236,11 @@ int32_t PIOS_USART_Init(uint32_t *usart_id, const struct pios_usart_cfg *cfg)
}
#endif
/* Configure USART Interrupts */
switch ((uint32_t)usart_dev->cfg->regs) {
case (uint32_t)USART1:
PIOS_USART_1_id = (uint32_t)usart_dev;
usart_dev->irq_channel = USART1_IRQn;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
break;
case (uint32_t)USART2:
PIOS_USART_2_id = (uint32_t)usart_dev;
usart_dev->irq_channel = USART2_IRQn;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
break;
case (uint32_t)USART3:
PIOS_USART_3_id = (uint32_t)usart_dev;
usart_dev->irq_channel = USART3_IRQn;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
break;
}
*usart_id = (uint32_t)usart_dev;
*local_id = (uint32_t)usart_dev;
PIOS_USART_SetIrqPrio(usart_dev, PIOS_IRQ_PRIO_MID);
*usart_id = (uint32_t)usart_dev;
return 0;
out_fail:
@ -258,7 +270,16 @@ static void PIOS_USART_Setup(struct pios_usart_dev *usart_dev)
}
/* Write new configuration */
USART_Init(usart_dev->cfg->regs, &usart_dev->init);
{ // fix parity stuff
USART_InitTypeDef init = usart_dev->init;
if ((init.USART_Parity != USART_Parity_No) && (init.USART_WordLength == USART_WordLength_8b)) {
init.USART_WordLength = USART_WordLength_9b;
}
USART_Init(usart_dev->cfg->regs, &init);
}
/*
* Re enable USART.
@ -301,6 +322,10 @@ static void PIOS_USART_ChangeBaud(uint32_t usart_id, uint32_t baud)
PIOS_Assert(valid);
if (usart_dev->config_locked) {
return;
}
/* Use our working copy of the usart init structure */
usart_dev->init.USART_BaudRate = baud;
@ -329,6 +354,10 @@ static void PIOS_USART_ChangeConfig(uint32_t usart_id,
PIOS_Assert(valid);
if (usart_dev->config_locked) {
return;
}
switch (word_len) {
case PIOS_COM_Word_length_8b:
usart_dev->init.USART_WordLength = USART_WordLength_8b;
@ -519,6 +548,9 @@ static int32_t PIOS_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param)
case PIOS_IOCTL_USART_SET_HALFDUPLEX:
USART_HalfDuplexCmd(usart_dev->cfg->regs, *(bool *)param ? ENABLE : DISABLE);
break;
case PIOS_IOCTL_USART_LOCK_CONFIG:
usart_dev->config_locked = *(bool *)param;
break;
default:
return COM_IOCTL_ENOSYS; /* unknown ioctl */
}

View File

@ -86,6 +86,9 @@ void PIOS_USB_HID_RegisterHidReport(const uint8_t *desc, uint16_t desc_size)
Hid_Report_Descriptor.Descriptor_Size = desc_size;
}
void PIOS_USBHOOK_Deactivate(void)
{}
#include "stm32f10x.h" /* __IO */
__IO uint8_t EXTI_Enable;

View File

@ -0,0 +1,39 @@
/**
******************************************************************************
*
* @file pios_architecture.h
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2013.
* @brief Architecture specific macros and definitions
* --
* @see The GNU Public License (GPL) Version 3
*
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef PIOS_ARCHITECTURE_H
#define PIOS_ARCHITECTURE_H
// defines for adc
#define PIOS_ADC_VOLTAGE_SCALE 3.30f / 4096.0f
// defines for Temp measurements
#define PIOS_ADC_STM32_TEMP_V25 0.76f /* V */
#define PIOS_ADC_STM32_TEMP_AVG_SLOPE 2.5f /* mV/C */
#define PIOS_CONVERT_VOLT_TO_CPU_TEMP(x) ((x - PIOS_ADC_STM32_TEMP_V25) * 1000.0f / PIOS_ADC_STM32_TEMP_AVG_SLOPE + 25.0f)
#endif /* PIOS_ARCHITECTURE_H */

View File

@ -0,0 +1,43 @@
/**
******************************************************************************
* @addtogroup PIOS PIOS Core hardware abstraction layer
* @{
* @addtogroup PIOS_DELAY Delay Functions
* @brief PiOS Delay functionality
* @{
*
* @file pios_delay_raw.h
* @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016-2017.
* The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @brief Settings functions header
* @see The GNU Public License (GPL) Version 3
*
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef PIOS_DELAY_RAW_H
#define PIOS_DELAY_RAW_H
/* these should be defined by CMSIS, but they aren't */
#define DWT_CTRL (*(volatile uint32_t *)0xe0001000)
#define CYCCNTENA (1 << 0)
#define DWT_CYCCNT (*(volatile uint32_t *)0xe0001004)
#define PIOS_DELAY_GetRaw() (DWT_CYCCNT)
extern uint32_t PIOS_DELAY_GetRawHz();
#endif /* PIOS_DELAY_RAW_H */

View File

@ -0,0 +1,53 @@
/**
******************************************************************************
*
* @file pios_servo_config.h
* @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017
* The OpenPilot Team, http://www.openpilot.org Copyright (C) 2013.
* @brief Architecture specific macros and definitions
* --
* @see The GNU Public License (GPL) Version 3
*
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef PIOS_SERVO_CONFIG_H_
#define PIOS_SERVO_CONFIG_H_
/**
* Generic servo pin configuration structure for an STM32F30X
*/
#define TIM_SERVO_CHANNEL_CONFIG(_timer, _channel, _gpio, _pin) \
{ \
.timer = _timer, \
.timer_chan = TIM_Channel_##_channel, \
.pin = { \
.gpio = GPIO##_gpio, \
.init = { \
.GPIO_Pin = GPIO_Pin_##_pin, \
.GPIO_Speed = GPIO_Speed_2MHz, \
.GPIO_Mode = GPIO_Mode_AF, \
.GPIO_OType = GPIO_OType_PP, \
.GPIO_PuPd = GPIO_PuPd_UP \
}, \
.pin_source = GPIO_PinSource##_pin, \
}, \
.remap = GPIO_AF_P##_gpio##_pin##_##_timer, \
}
#endif /* PIOS_SERVO_CONFIG_H_ */

View File

@ -0,0 +1,61 @@
/**
******************************************************************************
*
* @file pios_usart_config.h
* @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017
* @brief Architecture specific macros and definitions
* --
* @see The GNU Public License (GPL) Version 3
*
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef PIOS_USART_CONFIG_H_
#define PIOS_USART_CONFIG_H_
/**
* Generic USART configuration structure for an STM32F30x port.
*/
#define USART_CONFIG(_usart, _rx_gpio, _rx_pin, _tx_gpio, _tx_pin) \
{ \
.regs = _usart, \
.remap = GPIO_AF_##_usart, \
.rx = { \
.gpio = GPIO##_rx_gpio, \
.init = { \
.GPIO_Pin = GPIO_Pin_##_rx_pin, \
.GPIO_Mode = GPIO_Mode_AF, \
.GPIO_Speed = GPIO_Speed_50MHz, \
.GPIO_OType = GPIO_OType_PP, \
.GPIO_PuPd = GPIO_PuPd_UP, \
}, \
.pin_source = GPIO_PinSource##_rx_pin, \
}, \
.tx = { \
.gpio = GPIO##_tx_gpio, \
.init = { \
.GPIO_Pin = GPIO_Pin_##_tx_pin, \
.GPIO_Mode = GPIO_Mode_AF, \
.GPIO_Speed = GPIO_Speed_50MHz, \
.GPIO_OType = GPIO_OType_PP, \
.GPIO_PuPd = GPIO_PuPd_UP, \
}, \
.pin_source = GPIO_PinSource##_tx_pin, \
}, \
}
#endif /* PIOS_USART_CONFIG_H_ */

View File

@ -0,0 +1,78 @@
/**
******************************************************************************
*
* @file pios_ws2811_cfg.h
* @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017.
* @brief A driver for ws2811 rgb led controller.
* this is a port of the CleanFlight/BetaFlight implementation.
* @see The GNU Public License (GPL) Version 3
*
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef PIOS_WS2811_CFG_H_
#define PIOS_WS2811_CFG_H_
struct pios_ws2811_cfg {
TIM_TypeDef *timer;
uint8_t timer_chan;
struct stm32_gpio pin;
uint32_t remap;
uint16_t timer_dma_source;
DMA_Channel_TypeDef *dma_chan;
uint32_t dma_tcif;
uint8_t dma_irqn;
};
#define PIOS_WS2811_CONFIG(_timer, _channel, _gpio, _pin) \
{ \
.timer = _timer, \
.timer_chan = TIM_Channel_##_channel, \
.pin = { \
.gpio = GPIO##_gpio, \
.init = { \
.GPIO_Pin = GPIO_Pin_##_pin, \
.GPIO_Speed = GPIO_Speed_2MHz, \
.GPIO_Mode = GPIO_Mode_AF, \
.GPIO_OType = GPIO_OType_PP, \
.GPIO_PuPd = GPIO_PuPd_UP \
}, \
.pin_source = GPIO_PinSource##_pin, \
}, \
.remap = GPIO_AF_P##_gpio##_pin##_##_timer, \
.timer_dma_source = TIM_DMA_CC##_channel, \
.dma_chan = _EVAL4(DMA, _timer##_CH##_channel##_DMA_INSTANCE, _Channel, _timer##_CH##_channel##_DMA_CHANNEL), \
.dma_tcif = _EVAL4(DMA, _timer##_CH##_channel##_DMA_INSTANCE, _IT_TC, _timer##_CH##_channel##_DMA_CHANNEL), \
.dma_irqn = _EVAL5(DMA, _timer##_CH##_channel##_DMA_INSTANCE, _Channel, _timer##_CH##_channel##_DMA_CHANNEL, _IRQn), \
}
#define DMA0_Channel0 0
#define DMA0_IT_TC0 0
#define DMA0_Channel0_IRQn 0
void PIOS_WS2811_Init(uint32_t *dev_id, const struct pios_ws2811_cfg *ws2811_cfg);
void PIOS_WS2811_DMA_irq_handler();
#endif /* PIOS_WS2811_CFG_H_ */

View File

@ -0,0 +1,82 @@
/**
******************************************************************************
* @file stm32f30x_conf.h
* @author MCD Application Team
* @version V1.0.0
* @date 04-September-2012
* @brief Library configuration file.
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2012 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2
*
* 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.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM32F30X_CONF_H
#define __STM32F30X_CONF_H
/* Includes ------------------------------------------------------------------*/
/* Comment the line below to disable peripheral header file inclusion */
#include "stm32f30x_adc.h"
#include "stm32f30x_can.h"
#include "stm32f30x_crc.h"
#include "stm32f30x_comp.h"
#include "stm32f30x_dac.h"
#include "stm32f30x_dbgmcu.h"
#include "stm32f30x_dma.h"
#include "stm32f30x_exti.h"
#include "stm32f30x_flash.h"
#include "stm32f30x_gpio.h"
#include "stm32f30x_syscfg.h"
#include "stm32f30x_i2c.h"
#include "stm32f30x_iwdg.h"
#include "stm32f30x_opamp.h"
#include "stm32f30x_pwr.h"
#include "stm32f30x_rcc.h"
#include "stm32f30x_rtc.h"
#include "stm32f30x_spi.h"
#include "stm32f30x_tim.h"
#include "stm32f30x_usart.h"
#include "stm32f30x_wwdg.h"
#include "stm32f30x_misc.h" /* High level functions for NVIC and SysTick (add-on to CMSIS functions) */
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* Uncomment the line below to expanse the "assert_param" macro in the
Standard Peripheral Library drivers code */
/* #define USE_FULL_ASSERT 1 */
/* Exported macro ------------------------------------------------------------*/
#ifdef USE_FULL_ASSERT
/**
* @brief The assert_param macro is used for function's parameters check.
* @param expr: If expr is false, it calls assert_failed function which reports
* the name of the source file and the source line number of the call
* that failed. If expr is true, it returns no value.
* @retval None
*/
#define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__))
/* Exported functions ------------------------------------------------------- */
void assert_failed(uint8_t *file, uint32_t line);
#else
#define assert_param(expr) ((void)0)
#endif /* USE_FULL_ASSERT */
#endif /* __STM32F30X_CONF_H */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View File

@ -0,0 +1,197 @@
/******************** (C) COPYRIGHT 2010 STMicroelectronics ********************
* File Name : usb_conf.h
* Author : MCD Application Team
* Version : V3.2.1
* Date : 07/05/2010
* Description : Custom HID demo configuration file
********************************************************************************
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME.
* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*******************************************************************************/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __USB_CONF_H
#define __USB_CONF_H
/* Includes ------------------------------------------------------------------*/
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
/* External variables --------------------------------------------------------*/
#ifndef STM32F10X_CL
/*-------------------------------------------------------------*/
/* -------------- Buffer Description Table -----------------*/
/*-------------------------------------------------------------*/
/* buffer table base address */
/* buffer table base address */
#define BTABLE_ADDRESS (0x00)
/* EP0 */
/* rx/tx buffer base address */
#define ENDP0_RXADDR (0x20)
#define ENDP0_TXADDR (0x40)
/* EP1 */
/* rx/tx buffer base address */
#define ENDP1_TXADDR (0x60)
#define ENDP1_RXADDR (0x80)
/* EP2 */
/* rx/tx buffer base address */
#define ENDP2_TXADDR (0x100)
#define ENDP2_RXADDR (0x140)
/* EP3 */
/* rx/tx buffer base address */
#define ENDP3_TXADDR (0x180)
#define ENDP3_RXADDR (0x1C0)
/*-------------------------------------------------------------*/
/* ------------------- ISTR events -------------------------*/
/*-------------------------------------------------------------*/
/* IMR_MSK */
/* mask defining which events has to be handled */
/* by the device application software */
#define IMR_MSK \
(CNTR_CTRM | CNTR_WKUPM | CNTR_SUSPM | CNTR_ERRM | CNTR_SOFM \
| CNTR_ESOFM | CNTR_RESETM)
/* Provide a callback function for SOF so we can do early USB detection */
#define SOF_CALLBACK
/* Provide a callback function for SUSPend so we can notice a cable removal event */
#define SUSP_CALLBACK
#endif /* STM32F10X_CL */
#ifdef STM32F10X_CL
/*******************************************************************************
* FIFO Size Configuration
*
* (i) Dedicated data FIFO SPRAM of 1.25 Kbytes = 1280 bytes = 320 32-bits words
* available for the endpoints IN and OUT.
* Device mode features:
* -1 bidirectional CTRL EP 0
* -3 IN EPs to support any kind of Bulk, Interrupt or Isochronous transfer
* -3 OUT EPs to support any kind of Bulk, Interrupt or Isochronous transfer
*
* ii) Receive data FIFO size = RAM for setup packets +
* OUT endpoint control information +
* data OUT packets + miscellaneous
* Space = ONE 32-bits words
* --> RAM for setup packets = 4 * n + 6 space
* (n is the nbr of CTRL EPs the device core supports)
* --> OUT EP CTRL info = 1 space
* (one space for status information written to the FIFO along with each
* received packet)
* --> data OUT packets = (Largest Packet Size / 4) + 1 spaces
* (MINIMUM to receive packets)
* --> OR data OUT packets = at least 2*(Largest Packet Size / 4) + 1 spaces
* (if high-bandwidth EP is enabled or multiple isochronous EPs)
* --> miscellaneous = 1 space per OUT EP
* (one space for transfer complete status information also pushed to the
* FIFO with each endpoint's last packet)
*
* (iii)MINIMUM RAM space required for each IN EP Tx FIFO = MAX packet size for
* that particular IN EP. More space allocated in the IN EP Tx FIFO results
* in a better performance on the USB and can hide latencies on the AHB.
*
* (iv) TXn min size = 16 words. (n : Transmit FIFO index)
* (v) When a TxFIFO is not used, the Configuration should be as follows:
* case 1 : n > m and Txn is not used (n,m : Transmit FIFO indexes)
* --> Txm can use the space allocated for Txn.
* case2 : n < m and Txn is not used (n,m : Transmit FIFO indexes)
* --> Txn should be configured with the minimum space of 16 words
* (vi) The FIFO is used optimally when used TxFIFOs are allocated in the top
* of the FIFO.Ex: use EP1 and EP2 as IN instead of EP1 and EP3 as IN ones.
*******************************************************************************/
#define RX_FIFO_SIZE 128
#define TX0_FIFO_SIZE 64
#define TX1_FIFO_SIZE 64
#define TX2_FIFO_SIZE 16
#define TX3_FIFO_SIZE 16
/* OTGD-FS-DEVICE IP interrupts Enable definitions */
/* Uncomment the define to enable the selected interrupt */
// #define INTR_MODEMISMATCH
#define INTR_SOFINTR
#define INTR_RXSTSQLVL /* Mandatory */
// #define INTR_NPTXFEMPTY
// #define INTR_GINNAKEFF
// #define INTR_GOUTNAKEFF
// #define INTR_ERLYSUSPEND
#define INTR_USBSUSPEND /* Mandatory */
#define INTR_USBRESET /* Mandatory */
#define INTR_ENUMDONE /* Mandatory */
// #define INTR_ISOOUTDROP
// #define INTR_EOPFRAME
// #define INTR_EPMISMATCH
#define INTR_INEPINTR /* Mandatory */
#define INTR_OUTEPINTR /* Mandatory */
// #define INTR_INCOMPLISOIN
// #define INTR_INCOMPLISOOUT
#define INTR_WKUPINTR /* Mandatory */
/* OTGD-FS-DEVICE IP interrupts subroutines */
/* Comment the define to enable the selected interrupt subroutine and replace it
by user code */
#define INTR_MODEMISMATCH_Callback NOP_Process
#define INTR_SOFINTR_Callback NOP_Process
#define INTR_RXSTSQLVL_Callback NOP_Process
#define INTR_NPTXFEMPTY_Callback NOP_Process
#define INTR_NPTXFEMPTY_Callback NOP_Process
#define INTR_GINNAKEFF_Callback NOP_Process
#define INTR_GOUTNAKEFF_Callback NOP_Process
#define INTR_ERLYSUSPEND_Callback NOP_Process
#define INTR_USBSUSPEND_Callback NOP_Process
#define INTR_USBRESET_Callback NOP_Process
#define INTR_ENUMDONE_Callback NOP_Process
#define INTR_ISOOUTDROP_Callback NOP_Process
#define INTR_EOPFRAME_Callback NOP_Process
#define INTR_EPMISMATCH_Callback NOP_Process
#define INTR_INEPINTR_Callback NOP_Process
#define INTR_OUTEPINTR_Callback NOP_Process
#define INTR_INCOMPLISOIN_Callback NOP_Process
#define INTR_INCOMPLISOOUT_Callback NOP_Process
#define INTR_WKUPINTR_Callback NOP_Process
/* Isochronous data update */
#define INTR_RXSTSQLVL_ISODU_Callback NOP_Process
/* Isochronous transfer parameters */
/* Size of a single Isochronous buffer (size of a single transfer) */
#define ISOC_BUFFER_SZE 1
/* Number of sub-buffers (number of single buffers/transfers), should be even */
#define NUM_SUB_BUFFERS 2
#endif /* STM32F10X_CL */
/* CTR service routines */
/* associated to defined endpoints */
#define EP1_IN_Callback NOP_Process
#define EP2_IN_Callback NOP_Process
#define EP3_IN_Callback NOP_Process
#define EP4_IN_Callback NOP_Process
#define EP5_IN_Callback NOP_Process
#define EP6_IN_Callback NOP_Process
#define EP7_IN_Callback NOP_Process
#define EP1_OUT_Callback NOP_Process
#define EP2_OUT_Callback NOP_Process
#define EP3_OUT_Callback NOP_Process
#define EP4_OUT_Callback NOP_Process
#define EP5_OUT_Callback NOP_Process
#define EP6_OUT_Callback NOP_Process
#define EP7_OUT_Callback NOP_Process
#endif /*__USB_CONF_H*/
/******************* (C) COPYRIGHT 2010 STMicroelectronics *****END OF FILE****/

View File

@ -0,0 +1,63 @@
#
# Rules to (help) build the F30x device support.
#
# Directory containing this makefile
PIOS_DEVLIB := $(dir $(lastword $(MAKEFILE_LIST)))
MCU := cortex-m4
USE_USB ?= YES
LDSRC = $(PIOS_DEVLIB)link_memory.lds $(PIOS_DEVLIB)link_sections.lds
CDEFS += -D$(CHIP) -DSTM32F3
CDEFS += -DHSE_VALUE=$(OSCILLATOR_FREQ)
CDEFS += -DUSE_STDPERIPH_DRIVER
CDEFS += -DARM_MATH_CM4 -D__FPU_PRESENT=1
CDEFS += -DPIOS_TARGET_PROVIDES_FAST_HEAP
ARCHFLAGS += -mcpu=cortex-m4 -march=armv7e-m -mfpu=fpv4-sp-d16 -mfloat-abi=hard
# PIOS device library source and includes
PIOS_DEVLIB_SRC = $(sort $(wildcard $(PIOS_DEVLIB)*.c))
ifeq ($(PIOS_OMITS_USB),YES)
SRC += $(filter-out $(wildcard $(PIOS_DEVLIB)pios_usb*.c), $(PIOS_DEVLIB_SRC))
else
SRC += $(PIOS_DEVLIB_SRC)
endif
EXTRAINCDIRS += $(PIOS_DEVLIB)inc
# CMSIS for the F3
include $(PIOSCOMMON)/libraries/CMSIS/library.mk
CMSIS_DEVICEDIR := $(PIOS_DEVLIB)libraries/CMSIS3/Device/ST/STM32F30x
EXTRAINCDIRS += $(CMSIS_DEVICEDIR)/Include
# ST Peripheral library
PERIPHLIB = $(PIOS_DEVLIB)libraries/STM32F30x_StdPeriph_Driver
ALL_SPL_SOURCES = $(sort $(wildcard $(PERIPHLIB)/src/*.c))
SPL_SOURCES = $(filter-out %stm32f30x_can.c, $(ALL_SPL_SOURCES))
SRC += $(SPL_SOURCES)
EXTRAINCDIRS += $(PERIPHLIB)/inc
ifneq ($(PIOS_OMITS_USB),YES)
# ST USB Device library
USBDEVLIB = $(PIOS_DEVLIB)/libraries/STM32_USB-FS-Device_Driver
SRC += $(sort $(wildcard $(USBDEVLIB)/src/*.c))
EXTRAINCDIRS += $(USBDEVLIB)/inc
endif
#
# FreeRTOS
#
# If the application has included the generic FreeRTOS support, then add in
# the device-specific pieces of the code.
#
ifneq ($(FREERTOS_DIR),)
FREERTOS_PORTDIR := $(FREERTOS_DIR)
SRC += $(sort $(wildcard $(FREERTOS_PORTDIR)/portable/GCC/ARM_CM4F/*.c))
EXTRAINCDIRS += $(FREERTOS_PORTDIR)/portable/GCC/ARM_CM4F
include $(PIOSCOMMON)/libraries/msheap/library.mk
endif

View File

@ -0,0 +1,26 @@
#define SRAM_BANK_BASE 0x20000000
#define CCSRAM_BANK_BASE 0x10000000
#ifdef STM32F303xC
# define SRAM_BANK_SIZE 0x00A000
# define CCSRAM_BANK_SIZE 0x002000
#endif
#ifdef STM32F303xE
# define SRAM_BANK_SIZE 0x010000
# define CCSRAM_BANK_SIZE 0x004000
#endif
MEMORY
{
BD_INFO (r) : ORIGIN = (BL_BANK_BASE + BL_BANK_SIZE) - 0x80, LENGTH = 0x000080
#ifdef EE_BANK_BASE
EE_BANK (rx) : ORIGIN = EE_BANK_BASE, LENGTH = EE_BANK_SIZE
#endif /* EE_BANK_BASE */
#ifdef BOOTLOADER
FLASH (rx) : ORIGIN = BL_BANK_BASE, LENGTH = BL_BANK_SIZE
#else
FLASH (rx) : ORIGIN = FW_BANK_BASE, LENGTH = FW_BANK_SIZE
#endif
SRAM (rwx) : ORIGIN = SRAM_BANK_BASE, LENGTH = SRAM_BANK_SIZE
CCSRAM (rw) : ORIGIN = CCSRAM_BANK_BASE, LENGTH = CCSRAM_BANK_SIZE
}

View File

@ -0,0 +1,197 @@
/* Section Definitions */
SECTIONS
{
/*
* Vectors, code and constant data.
*/
.text :
{
PROVIDE (pios_isr_vector_table_base = .);
KEEP(*(.cpu_vectors)) /* CPU exception vectors */
KEEP(*(.io_vectors)) /* I/O interrupt vectors */
*(.text .text.* .gnu.linkonce.t.*)
*(.glue_7t) *(.glue_7)
*(.rodata .rodata* .gnu.linkonce.r.*)
KEEP(*(.keep))
} > FLASH
/*
* Init section for UAVObjects.
*/
.initcalluavobj.init :
{
. = ALIGN(4);
__uavobj_initcall_start = .;
KEEP(*(.initcalluavobj.init))
. = ALIGN(4);
__uavobj_initcall_end = .;
} >FLASH
/*
* Module init section section
*/
.initcallmodule.init :
{
. = ALIGN(4);
__module_initcall_start = .;
KEEP(*(.initcallmodule.init))
. = ALIGN(4);
__module_initcall_end = .;
} >FLASH
/*
* C++ exception handling.
*/
.ARM.extab :
{
*(.ARM.extab* .gnu.linkonce.armextab.*)
} > FLASH
.ARM.exidx :
{
__exidx_start = .;
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
__exidx_end = .;
} > FLASH
/*
* Markers for the end of the 'text' section and the in-flash start of
* non-constant data
*/
. = ALIGN(4);
_etext = .;
_sidata = .;
/*
* Board info structure, normally only generated by the bootloader but can
* be read by the application.
*/
PROVIDE(pios_board_info_blob = ORIGIN(BD_INFO));
.boardinfo :
{
. = ALIGN(4);
KEEP(*(.boardinfo))
. = ALIGN(ORIGIN(BD_INFO)+LENGTH(BD_INFO));
} > BD_INFO
/*
* Place the IRQ/bootstrap stack at the bottom of SRAM so that an overflow
* results in a hard fault.
*/
.istack (NOLOAD) :
{
. = ALIGN(4);
_irq_stack_end = . ;
*(.irqstack)
_irq_stack_top = . ;
} > CCSRAM
/*
* Non-const initialised data.
*/
.data : AT (_sidata)
{
. = ALIGN(4);
_sdata = .;
*(.data .data.*)
. = ALIGN(4);
_edata = . ;
} > SRAM
/*
* Uninitialised data (BSS + commons).
*/
.bss (NOLOAD) :
{
_sbss = . ;
*(SORT_BY_ALIGNMENT(.bss*))
*(COMMON)
_ebss = . ;
PROVIDE ( _end = _ebss ) ;
} > SRAM
/*
* The heap consumes the remainder of the SRAM.
*/
.heap (NOLOAD) :
{
. = ALIGN(4);
_sheap = . ;
/*
* This allows us to declare an object or objects up to the minimum acceptable
* heap size and receive a linker error if the space available for the heap is
* not sufficient.
*/
*(.heap)
/* extend the heap up to the top of SRAM */
. = ORIGIN(SRAM) + LENGTH(SRAM) - ABSOLUTE(_sheap);
_eheap = .;
} > SRAM
/*
* 'Fast' memory goes in the CCM SRAM
*/
.fast (NOLOAD) :
{
_sfast = . ;
*(.fast)
_efast = . ;
} > CCSRAM
/*
* The fastheap consumes the remainder of the CCSRAM.
*/
.fastheap (NOLOAD) :
{
. = ALIGN(4);
_sfastheap = . ;
/*
* This allows us to declare an object or objects up to the minimum acceptable
* heap size and receive a linker error if the space available for the heap is
* not sufficient.
*/
*(.fastheap)
/* extend the heap up to the top of SRAM */
. = ORIGIN(CCSRAM) + LENGTH(CCSRAM) - ABSOLUTE(_sfastheap);
_efastheap = .;
} > CCSRAM
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
}

View File

@ -0,0 +1,450 @@
/**
******************************************************************************
* @addtogroup PIOS PIOS Core hardware abstraction layer
* @{
* @addtogroup PIOS_ADC ADC Functions
* @brief STM32F30x ADC PIOS interface
* @{
*
* @file pios_adc.c
* @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017.
* @brief Analog to Digital conversion routines
* @see The GNU Public License (GPL) Version 3
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "pios.h"
#ifdef PIOS_INCLUDE_ADC
#include <pios_adc_priv.h>
#include <pios_adc.h>
#if !defined(PIOS_ADC_MAX_SAMPLES)
#define PIOS_ADC_MAX_SAMPLES 0
#endif
#if !defined(PIOS_ADC_MAX_OVERSAMPLING)
#define PIOS_ADC_MAX_OVERSAMPLING 0
#endif
#if !defined(PIOS_ADC_USE_ADC2)
#define PIOS_ADC_USE_ADC2 0
#endif
#if !defined(PIOS_ADC_NUM_CHANNELS)
#define PIOS_ADC_NUM_CHANNELS 0
#endif
struct pios_adc_pin_config {
GPIO_TypeDef *port;
uint32_t pin;
uint32_t channel;
bool initialize;
};
static const struct pios_adc_pin_config config[] = PIOS_DMA_PIN_CONFIG;
#define PIOS_ADC_NUM_PINS (sizeof(config) / sizeof(config[0]))
#define PIOS_ADC_DMA_BUFFER_SIZE (PIOS_ADC_MAX_SAMPLES * PIOS_ADC_NUM_PINS)
// Private types
enum pios_adc_dev_magic {
PIOS_ADC_DEV_MAGIC = 0x58375124,
};
struct adc_accumulator {
uint32_t accumulator;
uint32_t count;
};
struct pios_adc_dev {
const struct pios_adc_cfg *cfg;
ADCCallback callback_function;
#if defined(PIOS_INCLUDE_FREERTOS)
xQueueHandle data_queue;
#endif
enum pios_adc_dev_magic magic;
volatile uint16_t raw_data_buffer[PIOS_ADC_DMA_BUFFER_SIZE] __attribute__((aligned(4))); // Double buffer that DMA just used
struct adc_accumulator accumulator[PIOS_ADC_NUM_PINS];
};
struct pios_adc_dev *pios_adc_dev;
// Private functions
void PIOS_ADC_downsample_data();
static struct pios_adc_dev *PIOS_ADC_Allocate();
static bool PIOS_ADC_validate(struct pios_adc_dev *);
static void init_pins(struct pios_adc_dev *adc_dev);
static void init_dma(struct pios_adc_dev *adc_dev);
static void init_adc(struct pios_adc_dev *adc_dev);
static void init_pins(__attribute__((unused)) struct pios_adc_dev *adc_dev)
{
for (uint32_t i = 0; i < PIOS_ADC_NUM_PINS; ++i) {
if (!config[i].initialize) {
continue;
}
PIOS_ADC_PinSetup(i);
}
}
static void init_dma(struct pios_adc_dev *adc_dev)
{
/* Disable interrupts */
DMA_ITConfig(pios_adc_dev->cfg->dma.rx.channel, pios_adc_dev->cfg->dma.irq.flags, DISABLE);
/* Configure DMA channel */
DMA_DeInit(adc_dev->cfg->dma.rx.channel);
DMA_InitTypeDef DMAInit = adc_dev->cfg->dma.rx.init;
DMAInit.DMA_PeripheralBaseAddr = (uint32_t)&adc_dev->cfg->adc_dev->DR;
DMAInit.DMA_MemoryBaseAddr = (uint32_t)&pios_adc_dev->raw_data_buffer[0];
DMAInit.DMA_BufferSize = PIOS_ADC_DMA_BUFFER_SIZE;
DMAInit.DMA_DIR = DMA_DIR_PeripheralSRC;
DMAInit.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMAInit.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMAInit.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMAInit.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMAInit.DMA_Mode = DMA_Mode_Circular;
DMAInit.DMA_M2M = DMA_M2M_Disable;
DMA_Init(adc_dev->cfg->dma.rx.channel, &DMAInit); /* channel is actually stream ... */
/* enable DMA */
DMA_Cmd(adc_dev->cfg->dma.rx.channel, ENABLE);
/* Trigger interrupt when for half conversions too to indicate double buffer */
DMA_ITConfig(adc_dev->cfg->dma.rx.channel, DMA_IT_TC, ENABLE);
DMA_ITConfig(adc_dev->cfg->dma.rx.channel, DMA_IT_HT, ENABLE);
/* Configure DMA interrupt */
NVIC_InitTypeDef NVICInit = adc_dev->cfg->dma.irq.init;
NVIC_Init(&NVICInit);
}
static void init_adc(struct pios_adc_dev *adc_dev)
{
ADC_DeInit(adc_dev->cfg->adc_dev);
if (adc_dev->cfg->adc_dev == ADC1 || adc_dev->cfg->adc_dev == ADC2) {
RCC_ADCCLKConfig(RCC_ADC12PLLCLK_Div32);
} else {
RCC_ADCCLKConfig(RCC_ADC34PLLCLK_Div32);
}
ADC_VoltageRegulatorCmd(adc_dev->cfg->adc_dev, ENABLE);
PIOS_DELAY_WaituS(10);
ADC_SelectCalibrationMode(adc_dev->cfg->adc_dev, ADC_CalibrationMode_Single);
ADC_StartCalibration(adc_dev->cfg->adc_dev);
while (ADC_GetCalibrationStatus(adc_dev->cfg->adc_dev) != RESET) {
;
}
/* Do common ADC init */
ADC_CommonInitTypeDef ADC_CommonInitStructure;
ADC_CommonStructInit(&ADC_CommonInitStructure);
ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
ADC_CommonInitStructure.ADC_Clock = ADC_Clock_AsynClkMode;
ADC_CommonInitStructure.ADC_DMAMode = ADC_DMAMode_Circular;
ADC_CommonInitStructure.ADC_TwoSamplingDelay = 0;
ADC_DMAConfig(adc_dev->cfg->adc_dev, ADC_DMAMode_Circular);
ADC_CommonInit(adc_dev->cfg->adc_dev, &ADC_CommonInitStructure);
ADC_InitTypeDef ADC_InitStructure;
ADC_StructInit(&ADC_InitStructure);
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ContinuousConvMode = ADC_ContinuousConvMode_Enable;
ADC_InitStructure.ADC_ExternalTrigConvEvent = ADC_ExternalTrigConvEvent_0;
ADC_InitStructure.ADC_ExternalTrigEventEdge = ADC_ExternalTrigEventEdge_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfRegChannel = ((PIOS_ADC_NUM_PINS) /* >> 1*/);
ADC_Init(adc_dev->cfg->adc_dev, &ADC_InitStructure);
/* Enable DMA request */
ADC_DMACmd(adc_dev->cfg->adc_dev, ENABLE);
/* Configure input scan */
for (uint32_t i = 0; i < PIOS_ADC_NUM_PINS; i++) {
ADC_RegularChannelConfig(adc_dev->cfg->adc_dev,
config[i].channel,
i + 1,
ADC_SampleTime_61Cycles5); /* XXX this is totally arbitrary... */
}
ADC_Cmd(adc_dev->cfg->adc_dev, ENABLE);
while (!ADC_GetFlagStatus(adc_dev->cfg->adc_dev, ADC_FLAG_RDY)) {
;
}
ADC_StartConversion(adc_dev->cfg->adc_dev);
}
static bool PIOS_ADC_validate(struct pios_adc_dev *dev)
{
if (dev == NULL) {
return false;
}
return dev->magic == PIOS_ADC_DEV_MAGIC;
}
#if defined(PIOS_INCLUDE_FREERTOS)
static struct pios_adc_dev *PIOS_ADC_Allocate()
{
struct pios_adc_dev *adc_dev;
adc_dev = (struct pios_adc_dev *)pios_malloc(sizeof(*adc_dev));
if (!adc_dev) {
return NULL;
}
memset(adc_dev, 0, sizeof(*adc_dev));
adc_dev->magic = PIOS_ADC_DEV_MAGIC;
return adc_dev;
}
#else
#error Not implemented
static struct pios_adc_dev *PIOS_ADC_Allocate()
{
return (struct pios_adc_dev *)NULL;
}
#endif
/**
* @brief Init the ADC.
*/
int32_t PIOS_ADC_Init(const struct pios_adc_cfg *cfg)
{
PIOS_Assert(cfg);
pios_adc_dev = PIOS_ADC_Allocate();
if (pios_adc_dev == NULL) {
return -1;
}
pios_adc_dev->cfg = cfg;
pios_adc_dev->callback_function = NULL;
#if defined(PIOS_INCLUDE_FREERTOS)
pios_adc_dev->data_queue = NULL;
#endif
init_pins(pios_adc_dev);
init_dma(pios_adc_dev);
init_adc(pios_adc_dev);
return 0;
}
/**
* @brief Configure the ADC to run at a fixed oversampling
* @param[in] oversampling the amount of oversampling to run at
*/
void PIOS_ADC_Config(__attribute__((unused)) uint32_t oversampling)
{
/* we ignore this */
}
/**
* Returns value of an ADC Pin
* @param[in] pin number
* @return ADC pin value averaged over the set of samples since the last reading.
* @return -1 if pin doesn't exist
* @return -2 if no data acquired since last read
*/
int32_t last_conv_value;
int32_t PIOS_ADC_PinGet(uint32_t pin)
{
int32_t result;
/* Check if pin exists */
if (pin >= PIOS_ADC_NUM_PINS) {
return -1;
}
if (pios_adc_dev->accumulator[pin].accumulator <= 0) {
return -2;
}
/* return accumulated result and clear accumulator */
result = pios_adc_dev->accumulator[pin].accumulator / (pios_adc_dev->accumulator[pin].count ? : 1);
pios_adc_dev->accumulator[pin].accumulator = result;
pios_adc_dev->accumulator[pin].count = 1;
return result;
}
float PIOS_ADC_PinGetVolt(uint32_t pin)
{
return ((float)PIOS_ADC_PinGet(pin)) * PIOS_ADC_VOLTAGE_SCALE;
}
/**
* @brief Set a callback function that is executed whenever
* the ADC double buffer swaps
* @note Not currently supported.
*/
void PIOS_ADC_SetCallback(ADCCallback new_function)
{
pios_adc_dev->callback_function = new_function;
}
#if defined(PIOS_INCLUDE_FREERTOS)
/**
* @brief Register a queue to add data to when downsampled
* @note Not currently supported.
*/
void PIOS_ADC_SetQueue(xQueueHandle data_queue)
{
pios_adc_dev->data_queue = data_queue;
}
#endif
/**
* @brief Return the address of the downsampled data buffer
* @note Not currently supported.
*/
float *PIOS_ADC_GetBuffer(void)
{
return NULL;
}
/**
* @brief Return the address of the raw data data buffer
* @note Not currently supported.
*/
int16_t *PIOS_ADC_GetRawBuffer(void)
{
return NULL;
}
/**
* @brief Return the amount of over sampling
* @note Not currently supported (always returns 1)
*/
uint8_t PIOS_ADC_GetOverSampling(void)
{
return 1;
}
/**
* @brief Set the fir coefficients. Takes as many samples as the
* current filter order plus one (normalization)
*
* @param new_filter Array of adc_oversampling floats plus one for the
* filter coefficients
* @note Not currently supported.
*/
void PIOS_ADC_SetFIRCoefficients(__attribute__((unused)) float *new_filter)
{
// not implemented
}
/**
* @brief accumulate the data for each of the channels.
*/
void accumulate(struct pios_adc_dev *dev, volatile uint16_t *buffer)
{
volatile uint16_t *sp = buffer;
/*
* Accumulate sampled values.
*/
int count = (PIOS_ADC_MAX_SAMPLES / 2);
while (count--) {
for (uint32_t i = 0; i < PIOS_ADC_NUM_PINS; ++i) {
dev->accumulator[i].accumulator += *sp++;
dev->accumulator[i].count++;
/*
* If the accumulator reaches half-full, rescale in order to
* make more space.
*/
if (dev->accumulator[i].accumulator >= (((uint32_t)1) << 31)) {
dev->accumulator[i].accumulator /= 2;
dev->accumulator[i].count /= 2;
}
}
}
#if defined(PIOS_INCLUDE_FREERTOS)
// XXX should do something with this
if (pios_adc_dev->data_queue) {
static portBASE_TYPE xHigherPriorityTaskWoken;
// xQueueSendFromISR(pios_adc_dev->data_queue, pios_adc_dev->downsampled_buffer, &xHigherPriorityTaskWoken);
portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
}
#endif
// if(pios_adc_dev->callback_function)
// pios_adc_dev->callback_function(pios_adc_dev->downsampled_buffer);
}
/**
* @brief Interrupt on buffer flip.
*
* The hardware is done with the 'other' buffer, so we can pass it to the accumulator.
*/
void PIOS_ADC_DMA_Handler(void)
{
if (!PIOS_ADC_validate(pios_adc_dev)) {
return;
}
if (DMA_GetFlagStatus(pios_adc_dev->cfg->full_flag)) { // whole double buffer filled
DMA_ClearFlag(pios_adc_dev->cfg->full_flag);
accumulate(pios_adc_dev, &pios_adc_dev->raw_data_buffer[PIOS_ADC_DMA_BUFFER_SIZE / 2]);
} else if (DMA_GetFlagStatus(pios_adc_dev->cfg->half_flag)) {
DMA_ClearFlag(pios_adc_dev->cfg->half_flag);
accumulate(pios_adc_dev, &pios_adc_dev->raw_data_buffer[0]);
} else {
// This should not happen, probably due to transfer errors
DMA_ClearFlag(pios_adc_dev->cfg->dma.irq.flags);
}
}
void PIOS_ADC_PinSetup(uint32_t pin)
{
if (config[pin].port != NULL && pin < PIOS_ADC_NUM_PINS) {
/* Setup analog pin */
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_Pin = config[pin].pin;
GPIO_Init(config[pin].port, &GPIO_InitStructure);
}
}
#endif /* PIOS_INCLUDE_ADC */
/**
* @}
* @}
*/

View File

@ -0,0 +1,111 @@
/**
******************************************************************************
* @addtogroup PIOS PIOS Core hardware abstraction layer
* @{
* @addtogroup PIOS_BKP Backup SRAM functions
* @brief Hardware abstraction layer for backup sram
* @{
*
* @file pios_bkp.c
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2013.
* @brief IAP functions
* @see The GNU Public License (GPL) Version 3
*
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <pios.h>
#include <pios_bkp.h>
#include <stm32f30x_rtc.h>
/****************************************************************************************
* Header files
****************************************************************************************/
/*****************************************************************************************
* Public Definitions/Macros
****************************************************************************************/
/****************************************************************************************
* Public Functions
****************************************************************************************/
const uint32_t pios_bkp_registers_map[] = {
RTC_BKP_DR0,
RTC_BKP_DR1,
RTC_BKP_DR2,
RTC_BKP_DR3,
RTC_BKP_DR4,
RTC_BKP_DR5,
RTC_BKP_DR6,
RTC_BKP_DR7,
RTC_BKP_DR8,
RTC_BKP_DR9,
RTC_BKP_DR10,
RTC_BKP_DR11,
RTC_BKP_DR12,
RTC_BKP_DR13,
RTC_BKP_DR14,
RTC_BKP_DR15,
};
#define PIOS_BKP_REGISTERS_COUNT NELEMENTS(pios_bkp_registers_map)
void PIOS_BKP_Init(void)
{
/* Enable CRC clock */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_CRC, ENABLE);
/* Enable PWR and BKP clock */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
/* Clear Tamper pin Event(TE) pending flag */
RTC_ClearFlag(RTC_FLAG_TAMP1F);
}
uint16_t PIOS_BKP_ReadRegister(uint32_t regnumber)
{
if (PIOS_BKP_REGISTERS_COUNT < regnumber) {
PIOS_Assert(0);
} else {
return (uint16_t)RTC_ReadBackupRegister(pios_bkp_registers_map[regnumber]);
}
}
void PIOS_BKP_WriteRegister(uint32_t regnumber, uint16_t data)
{
if (PIOS_BKP_REGISTERS_COUNT < regnumber) {
PIOS_Assert(0);
} else {
RTC_WriteBackupRegister(pios_bkp_registers_map[regnumber], (uint32_t)data);
}
}
void PIOS_BKP_EnableWrite(void)
{
/* Enable write access to Backup domain */
PWR_BackupAccessCmd(ENABLE);
}
void PIOS_BKP_DisableWrite(void)
{
/* Enable write access to Backup domain */
PWR_BackupAccessCmd(DISABLE);
}
/****************************************************************************************
* Public Data
****************************************************************************************/

View File

@ -0,0 +1,127 @@
/**
******************************************************************************
* @addtogroup PIOS PIOS Core hardware abstraction layer
* @{
* @addtogroup PIOS_BOOTLOADER Functions
* @brief Bootloader Helper Functions
*
*
* @file pios_bl_helper.c
* @author The LibrePilot Project, http://www.librepilot.org Copyright(C) 2017.
* The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @see The GNU Public License (GPL) Version 3
*
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <pios.h>
#ifdef PIOS_INCLUDE_BL_HELPER
#include <pios_board_info.h>
#include <stm32f30x_flash.h>
#include <stdbool.h>
uint8_t *PIOS_BL_HELPER_FLASH_If_Read(uint32_t SectorAddress)
{
return (uint8_t *)(SectorAddress);
}
#if defined(PIOS_INCLUDE_BL_HELPER_WRITE_SUPPORT)
static bool erase_flash(uint32_t startAddress, uint32_t endAddress);
uint8_t PIOS_BL_HELPER_FLASH_Ini()
{
FLASH_Unlock();
return 1;
}
uint8_t PIOS_BL_HELPER_FLASH_Start()
{
const struct pios_board_info *bdinfo = &pios_board_info_blob;
uint32_t startAddress = bdinfo->fw_base;
uint32_t endAddress = bdinfo->fw_base + bdinfo->fw_size + bdinfo->desc_size;
bool success = erase_flash(startAddress, endAddress);
return (success) ? 1 : 0;
}
uint8_t PIOS_BL_HELPER_FLASH_Erase_Bootloader()
{
/// Bootloader memory space erase
uint32_t startAddress = BL_BANK_BASE;
uint32_t endAddress = BL_BANK_BASE + BL_BANK_SIZE;
bool success = erase_flash(startAddress, endAddress);
return (success) ? 1 : 0;
}
static bool erase_flash(uint32_t startAddress, uint32_t endAddress)
{
uint32_t pageAddress = startAddress;
uint8_t fail = false;
while ((pageAddress < endAddress) && (fail == false)) {
for (int retry = 0; retry < MAX_DEL_RETRYS; ++retry) {
if (FLASH_ErasePage(pageAddress) == FLASH_COMPLETE) {
fail = false;
break;
} else {
fail = true;
}
}
pageAddress += 2048;
}
return !fail;
}
#endif /* if defined(PIOS_INCLUDE_BL_HELPER_WRITE_SUPPORT) */
uint32_t PIOS_BL_HELPER_CRC_Memory_Calc()
{
const struct pios_board_info *bdinfo = &pios_board_info_blob;
PIOS_BL_HELPER_CRC_Ini();
CRC_ResetDR();
CRC_CalcBlockCRC((uint32_t *)bdinfo->fw_base, (bdinfo->fw_size) >> 2);
return CRC_GetCRC();
}
void PIOS_BL_HELPER_FLASH_Read_Description(uint8_t *array, uint8_t size)
{
const struct pios_board_info *bdinfo = &pios_board_info_blob;
uint8_t x = 0;
if (size > bdinfo->desc_size) {
size = bdinfo->desc_size;
}
for (uint32_t i = bdinfo->fw_base + bdinfo->fw_size; i < bdinfo->fw_base + bdinfo->fw_size + size; ++i) {
array[x] = *PIOS_BL_HELPER_FLASH_If_Read(i);
++x;
}
}
void PIOS_BL_HELPER_CRC_Ini()
{
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_CRC, ENABLE);
}
#endif /* PIOS_INCLUDE_BL_HELPER */

View File

@ -0,0 +1,178 @@
/**
******************************************************************************
* @addtogroup PIOS PIOS Core hardware abstraction layer
* @{
* @defgroup PIOS_DEBUG Debugging Functions
* @brief Debugging functionality
* @{
*
* @file pios_debug.c
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2013.
* @brief Debugging Functions
* @see The GNU Public License (GPL) Version 3
*
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "pios.h"
// Global variables
const char *PIOS_DEBUG_AssertMsg = "ASSERT FAILED";
#ifdef PIOS_ENABLE_DEBUG_PINS
static const struct pios_tim_channel *debug_channels;
static uint8_t debug_num_channels;
#endif /* PIOS_ENABLE_DEBUG_PINS */
/**
* Initialise Debug-features
*/
void PIOS_DEBUG_Init(__attribute__((unused)) const struct pios_tim_channel *channels, __attribute__((unused)) uint8_t num_channels)
{
#ifdef PIOS_ENABLE_DEBUG_PINS
PIOS_Assert(channels);
PIOS_Assert(num_channels);
/* Store away the GPIOs we've been given */
debug_channels = channels;
debug_num_channels = num_channels;
/* Configure the GPIOs we've been given */
for (uint8_t i = 0; i < num_channels; i++) {
const struct pios_tim_channel *chan = &channels[i];
// Initialise pins as standard output pins
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = chan->pin.init.GPIO_Pin;
/* Initialize the GPIO */
GPIO_Init(chan->pin.gpio, &GPIO_InitStructure);
/* Set the pin low */
GPIO_WriteBit(chan->pin.gpio, chan->pin.init.GPIO_Pin, Bit_RESET);
}
#endif // PIOS_ENABLE_DEBUG_PINS
}
/**
* Set debug-pin high
* \param pin 0 for S1 output
*/
void PIOS_DEBUG_PinHigh(__attribute__((unused)) uint8_t pin)
{
#ifdef PIOS_ENABLE_DEBUG_PINS
if (!debug_channels || pin >= debug_num_channels) {
return;
}
const struct pios_tim_channel *chan = &debug_channels[pin];
GPIO_WriteBit(chan->pin.gpio, chan->pin.init.GPIO_Pin, Bit_SET);
#endif // PIOS_ENABLE_DEBUG_PINS
}
/**
* Set debug-pin low
* \param pin 0 for S1 output
*/
void PIOS_DEBUG_PinLow(__attribute__((unused)) uint8_t pin)
{
#ifdef PIOS_ENABLE_DEBUG_PINS
if (!debug_channels || pin >= debug_num_channels) {
return;
}
const struct pios_tim_channel *chan = &debug_channels[pin];
GPIO_WriteBit(chan->pin.gpio, chan->pin.init.GPIO_Pin, Bit_RESET);
#endif // PIOS_ENABLE_DEBUG_PINS
}
void PIOS_DEBUG_PinValue8Bit(__attribute__((unused)) uint8_t value)
{
#ifdef PIOS_ENABLE_DEBUG_PINS
if (!debug_channels) {
return;
}
#pragma message("This code is not portable and should be revised")
PIOS_Assert(0);
uint32_t bsrr_l = (((~value) & 0x0F) << (16 + 6)) | ((value & 0x0F) << 6);
uint32_t bsrr_h = (((~value) & 0xF0) << (16 + 6 - 4)) | ((value & 0xF0) << (6 - 4));
PIOS_IRQ_Disable();
/*
* This is sketchy since it assumes a particular ordering
* and bitwise layout of the channels provided to the debug code.
*/
// debug_channels[0].pin.gpio->BSRR = bsrr_l;
// debug_channels[4].pin.gpio->BSRR = bsrr_h;
PIOS_IRQ_Enable();
#endif // PIOS_ENABLE_DEBUG_PINS
}
void PIOS_DEBUG_PinValue4BitL(__attribute__((unused)) uint8_t value)
{
#ifdef PIOS_ENABLE_DEBUG_PINS
if (!debug_channels) {
return;
}
#pragma message("This code is not portable and should be revised")
PIOS_Assert(0);
/*
* This is sketchy since it assumes a particular ordering
* and bitwise layout of the channels provided to the debug code.
*/
uint32_t bsrr_l = ((~(value & 0x0F) << (16 + 6))) | ((value & 0x0F) << 6);
// debug_channels[0].pin.gpio->BSRR = bsrr_l;
#endif // PIOS_ENABLE_DEBUG_PINS
}
/**
* Report a serious error and halt
*/
void PIOS_DEBUG_Panic(__attribute__((unused)) const char *msg)
{
#ifdef PIOS_INCLUDE_DEBUG_CONSOLE
register int *lr asm ("lr"); // Link-register holds the PC of the caller
DEBUG_PRINTF(0, "\r%s @0x%x\r", msg, lr);
#endif
// Stay put
while (1) {
;
}
}
/**
* @}
* @}
*/

View File

@ -0,0 +1,184 @@
/**
******************************************************************************
* @addtogroup PIOS PIOS Core hardware abstraction layer
* @{
* @addtogroup PIOS_DELAY Delay Functions
* @brief PiOS Delay functionality
* @{
*
* @file pios_delay.c
* @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016.
* Michael Smith Copyright (C) 2012
* @brief Delay Functions
* - Provides a micro-second granular delay using the CPU
* cycle counter.
* @see The GNU Public License (GPL) Version 3
*
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <pios.h>
#ifdef PIOS_INCLUDE_DELAY
/* cycles per microsecond */
static uint32_t us_ticks;
static uint32_t raw_hz;
/**
* Initialises the Timer used by PIOS_DELAY functions.
*
* \return always zero (success)
*/
int32_t PIOS_DELAY_Init(void)
{
RCC_ClocksTypeDef clocks;
/* compute the number of system clocks per microsecond */
RCC_GetClocksFreq(&clocks);
us_ticks = clocks.SYSCLK_Frequency / 1000000;
PIOS_DEBUG_Assert(us_ticks > 1);
raw_hz = clocks.SYSCLK_Frequency;
/* turn on access to the DWT registers */
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
/* enable the CPU cycle counter */
DWT_CTRL |= CYCCNTENA;
return 0;
}
/**
* Waits for a specific number of uS
*
* Example:<BR>
* \code
* // Wait for 500 uS
* PIOS_DELAY_Wait_uS(500);
* \endcode
* \param[in] uS delay
* \return < 0 on errors
*/
int32_t PIOS_DELAY_WaituS(uint32_t uS)
{
uint32_t elapsed = 0;
uint32_t last_count = PIOS_DELAY_GetRaw();
for (;;) {
uint32_t current_count = PIOS_DELAY_GetRaw();
uint32_t elapsed_uS;
/* measure the time elapsed since the last time we checked */
elapsed += current_count - last_count;
last_count = current_count;
/* convert to microseconds */
elapsed_uS = elapsed / us_ticks;
if (elapsed_uS >= uS) {
break;
}
/* reduce the delay by the elapsed time */
uS -= elapsed_uS;
/* keep fractional microseconds for the next iteration */
elapsed %= us_ticks;
}
/* No error */
return 0;
}
/**
* Waits for a specific number of mS
*
* Example:<BR>
* \code
* // Wait for 500 mS
* PIOS_DELAY_Wait_mS(500);
* \endcode
* \param[in] mS delay (1..65535 milliseconds)
* \return < 0 on errors
*/
int32_t PIOS_DELAY_WaitmS(uint32_t mS)
{
while (mS--) {
PIOS_DELAY_WaituS(1000);
}
/* No error */
return 0;
}
/**
* @brief Query the Delay timer for the current uS
* @return A microsecond value
*/
uint32_t PIOS_DELAY_GetuS()
{
return PIOS_DELAY_GetRaw() / us_ticks;
}
/**
* @brief Calculate time in microseconds since a previous time
* @param[in] t previous time
* @return time in us since previous time t.
*/
uint32_t PIOS_DELAY_GetuSSince(uint32_t t)
{
return PIOS_DELAY_GetuS() - t;
}
/**
* @brief Get the raw delay timer frequency
* @return raw delay timer frequency in Hz
*/
uint32_t PIOS_DELAY_GetRawHz()
{
return raw_hz;
}
/**
* @brief Compare to raw times to and convert to us
* @return A microsecond value
*/
uint32_t PIOS_DELAY_DiffuS(uint32_t raw)
{
uint32_t diff = PIOS_DELAY_GetRaw() - raw;
return diff / us_ticks;
}
#if !defined(PIOS_EXCLUDE_ADVANCED_FEATURES)
/**
* @brief Subtract two raw times and convert to us.
* @return Interval between raw times in microseconds
*/
uint32_t PIOS_DELAY_DiffuS2(uint32_t raw, uint32_t later)
{
return (later - raw) / us_ticks;
}
#endif /* !defined(PIOS_EXCLUDE_ADVANCED_FEATURES) */
#endif /* PIOS_INCLUDE_DELAY */
/**
* @}
* @}
*/

View File

@ -0,0 +1,326 @@
/**
******************************************************************************
*
* @addtogroup PIOS PIOS Core hardware abstraction layer
* @{
* @addtogroup PIOS_EXTI External Interrupt Handlers
* @brief External interrupt handler functions
* @{
*
* @file pios_exti.c
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @brief External Interrupt Handlers
* @see The GNU Public License (GPL) Version 3
*
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "pios.h"
#ifdef PIOS_INCLUDE_EXTI
#define EXTI_MAX_LINES 16
static pios_exti_vector_t pios_exti_vector[EXTI_MAX_LINES];
static uint8_t PIOS_EXTI_line_to_index(uint32_t line)
{
switch (line) {
case EXTI_Line0: return 0;
case EXTI_Line1: return 1;
case EXTI_Line2: return 2;
case EXTI_Line3: return 3;
case EXTI_Line4: return 4;
case EXTI_Line5: return 5;
case EXTI_Line6: return 6;
case EXTI_Line7: return 7;
case EXTI_Line8: return 8;
case EXTI_Line9: return 9;
case EXTI_Line10: return 10;
case EXTI_Line11: return 11;
case EXTI_Line12: return 12;
case EXTI_Line13: return 13;
case EXTI_Line14: return 14;
case EXTI_Line15: return 15;
}
PIOS_Assert(0);
return 0xFF;
}
uint8_t PIOS_EXTI_gpio_port_to_exti_source_port(GPIO_TypeDef *gpio_port)
{
switch ((uint32_t)gpio_port) {
case (uint32_t)GPIOA: return EXTI_PortSourceGPIOA;
case (uint32_t)GPIOB: return EXTI_PortSourceGPIOB;
case (uint32_t)GPIOC: return EXTI_PortSourceGPIOC;
case (uint32_t)GPIOD: return EXTI_PortSourceGPIOD;
case (uint32_t)GPIOE: return EXTI_PortSourceGPIOE;
case (uint32_t)GPIOF: return EXTI_PortSourceGPIOF;
}
PIOS_Assert(0);
return 0xFF;
}
uint8_t PIOS_EXTI_gpio_pin_to_exti_source_pin(uint32_t gpio_pin)
{
switch ((uint32_t)gpio_pin) {
case GPIO_Pin_0: return GPIO_PinSource0;
case GPIO_Pin_1: return GPIO_PinSource1;
case GPIO_Pin_2: return GPIO_PinSource2;
case GPIO_Pin_3: return GPIO_PinSource3;
case GPIO_Pin_4: return GPIO_PinSource4;
case GPIO_Pin_5: return GPIO_PinSource5;
case GPIO_Pin_6: return GPIO_PinSource6;
case GPIO_Pin_7: return GPIO_PinSource7;
case GPIO_Pin_8: return GPIO_PinSource8;
case GPIO_Pin_9: return GPIO_PinSource9;
case GPIO_Pin_10: return GPIO_PinSource10;
case GPIO_Pin_11: return GPIO_PinSource11;
case GPIO_Pin_12: return GPIO_PinSource12;
case GPIO_Pin_13: return GPIO_PinSource13;
case GPIO_Pin_14: return GPIO_PinSource14;
case GPIO_Pin_15: return GPIO_PinSource15;
}
PIOS_Assert(0);
return 0xFF;
}
int32_t PIOS_EXTI_Init(const struct pios_exti_cfg *cfg)
{
PIOS_Assert(cfg);
/* Connect this config to the requested vector */
uint8_t line_index = PIOS_EXTI_line_to_index(cfg->line);
if (pios_exti_vector[line_index]) {
/* Someone else already has this mapped */
return -1;
}
/* Bind the vector to the exti line */
pios_exti_vector[line_index] = cfg->vector;
/* Initialize the GPIO pin */
GPIO_Init(cfg->pin.gpio, (GPIO_InitTypeDef *)&cfg->pin.init);
/* Set up the EXTI interrupt source */
uint8_t exti_source_port = PIOS_EXTI_gpio_port_to_exti_source_port(cfg->pin.gpio);
/* Following is not entirely correct! There is cfg->pin.pin_source to serve this purpose, and GPIO_Pin can also contain more than one bit set */
uint8_t exti_source_pin = PIOS_EXTI_gpio_pin_to_exti_source_pin(cfg->pin.init.GPIO_Pin);
SYSCFG_EXTILineConfig(exti_source_port, exti_source_pin);
EXTI_Init((EXTI_InitTypeDef *)&cfg->exti.init);
/* Enable the interrupt channel */
NVIC_Init((NVIC_InitTypeDef *)&cfg->irq.init);
return 0;
}
int32_t PIOS_EXTI_DeInit(const struct pios_exti_cfg *cfg)
{
uint8_t line_index = PIOS_EXTI_line_to_index(cfg->line);
if (pios_exti_vector[line_index] == cfg->vector) {
EXTI_InitTypeDef disable = cfg->exti.init;
disable.EXTI_LineCmd = DISABLE;
EXTI_Init(&disable);
pios_exti_vector[line_index] = 0;
return 0;
}
return -1;
}
static bool PIOS_EXTI_generic_irq_handler(uint8_t line_index)
{
if (pios_exti_vector[line_index]) {
return pios_exti_vector[line_index]();
}
/* Unconfigured interrupt just fired! */
return false;
}
/* Bind Interrupt Handlers */
#ifdef PIOS_INCLUDE_FREERTOS
#define PIOS_EXTI_HANDLE_LINE(line, woken) \
if (EXTI_GetITStatus(EXTI_Line##line) != RESET) { \
EXTI_ClearITPendingBit(EXTI_Line##line); \
woken = PIOS_EXTI_generic_irq_handler(line) ? pdTRUE : woken; \
}
#else
#define PIOS_EXTI_HANDLE_LINE(line, woken) \
if (EXTI_GetITStatus(EXTI_Line##line) != RESET) { \
EXTI_ClearITPendingBit(EXTI_Line##line); \
PIOS_EXTI_generic_irq_handler(line); \
}
#endif
static void PIOS_EXTI_0_irq_handler(void)
{
#ifdef PIOS_INCLUDE_FREERTOS
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
#else
bool xHigherPriorityTaskWoken;
#endif
PIOS_EXTI_HANDLE_LINE(0, xHigherPriorityTaskWoken);
#ifdef PIOS_INCLUDE_FREERTOS
portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
#endif
}
void EXTI0_IRQHandler(void) __attribute__((alias("PIOS_EXTI_0_irq_handler")));
static void PIOS_EXTI_1_irq_handler(void)
{
#ifdef PIOS_INCLUDE_FREERTOS
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
#else
bool xHigherPriorityTaskWoken;
#endif
PIOS_EXTI_HANDLE_LINE(1, xHigherPriorityTaskWoken);
#ifdef PIOS_INCLUDE_FREERTOS
portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
#endif
}
void EXTI1_IRQHandler(void) __attribute__((alias("PIOS_EXTI_1_irq_handler")));
static void PIOS_EXTI_2_irq_handler(void)
{
#ifdef PIOS_INCLUDE_FREERTOS
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
#else
bool xHigherPriorityTaskWoken;
#endif
PIOS_EXTI_HANDLE_LINE(2, xHigherPriorityTaskWoken);
#ifdef PIOS_INCLUDE_FREERTOS
portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
#endif
}
void EXTI2_IRQHandler(void) __attribute__((alias("PIOS_EXTI_2_irq_handler")));
static void PIOS_EXTI_3_irq_handler(void)
{
#ifdef PIOS_INCLUDE_FREERTOS
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
#else
bool xHigherPriorityTaskWoken;
#endif
PIOS_EXTI_HANDLE_LINE(3, xHigherPriorityTaskWoken);
#ifdef PIOS_INCLUDE_FREERTOS
portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
#endif
}
void EXTI3_IRQHandler(void) __attribute__((alias("PIOS_EXTI_3_irq_handler")));
static void PIOS_EXTI_4_irq_handler(void)
{
#ifdef PIOS_INCLUDE_FREERTOS
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
#else
bool xHigherPriorityTaskWoken;
#endif
PIOS_EXTI_HANDLE_LINE(4, xHigherPriorityTaskWoken);
#ifdef PIOS_INCLUDE_FREERTOS
portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
#endif
}
void EXTI4_IRQHandler(void) __attribute__((alias("PIOS_EXTI_4_irq_handler")));
static void PIOS_EXTI_9_5_irq_handler(void)
{
#ifdef PIOS_INCLUDE_FREERTOS
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
#else
bool xHigherPriorityTaskWoken;
#endif
PIOS_EXTI_HANDLE_LINE(5, xHigherPriorityTaskWoken);
PIOS_EXTI_HANDLE_LINE(6, xHigherPriorityTaskWoken);
PIOS_EXTI_HANDLE_LINE(7, xHigherPriorityTaskWoken);
PIOS_EXTI_HANDLE_LINE(8, xHigherPriorityTaskWoken);
PIOS_EXTI_HANDLE_LINE(9, xHigherPriorityTaskWoken);
#ifdef PIOS_INCLUDE_FREERTOS
portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
#endif
}
void EXTI9_5_IRQHandler(void) __attribute__((alias("PIOS_EXTI_9_5_irq_handler")));
static void PIOS_EXTI_15_10_irq_handler(void)
{
#ifdef PIOS_INCLUDE_FREERTOS
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
#else
bool xHigherPriorityTaskWoken;
#endif
PIOS_EXTI_HANDLE_LINE(10, xHigherPriorityTaskWoken);
PIOS_EXTI_HANDLE_LINE(11, xHigherPriorityTaskWoken);
PIOS_EXTI_HANDLE_LINE(12, xHigherPriorityTaskWoken);
PIOS_EXTI_HANDLE_LINE(13, xHigherPriorityTaskWoken);
PIOS_EXTI_HANDLE_LINE(14, xHigherPriorityTaskWoken);
PIOS_EXTI_HANDLE_LINE(15, xHigherPriorityTaskWoken);
#ifdef PIOS_INCLUDE_FREERTOS
portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
#endif
}
void EXTI15_10_IRQHandler(void) __attribute__((alias("PIOS_EXTI_15_10_irq_handler")));
#endif /* PIOS_INCLUDE_EXTI */
/**
* @}
* @}
*/

View File

@ -0,0 +1,304 @@
/**
******************************************************************************
*
* @file pios_flash_internal.c
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2013.
* @brief brief goes here.
* --
* @see The GNU Public License (GPL) Version 3
*
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "pios.h"
#ifdef PIOS_INCLUDE_FLASH_INTERNAL
#include "stm32f30x_flash.h"
#include "pios_flash_internal_priv.h"
#include "pios_flash.h"
#include <stdbool.h>
struct device_flash_sector {
uint32_t start;
uint32_t size;
uint16_t st_sector;
};
static bool PIOS_Flash_Internal_GetSectorInfo(uint32_t address, uint8_t *sector_number, uint32_t *sector_start, uint32_t *sector_size)
{
uint16_t sector = (address - 0x08000000) / 2048;
if (sector <= 127) {
/* address lies within this sector */
*sector_number = sector;
*sector_start = sector * 2048 + 0x08000000;
*sector_size = 2048;
return true;
}
return false;
}
enum pios_internal_flash_dev_magic {
PIOS_INTERNAL_FLASH_DEV_MAGIC = 0x33445902,
};
struct pios_internal_flash_dev {
enum pios_internal_flash_dev_magic magic;
#if defined(PIOS_INCLUDE_FREERTOS)
xSemaphoreHandle transaction_lock;
#endif /* defined(PIOS_INCLUDE_FREERTOS) */
};
static bool PIOS_Flash_Internal_Validate(struct pios_internal_flash_dev *flash_dev)
{
return flash_dev && (flash_dev->magic == PIOS_INTERNAL_FLASH_DEV_MAGIC);
}
#if defined(PIOS_INCLUDE_FREERTOS)
static struct pios_internal_flash_dev *PIOS_Flash_Internal_alloc(void)
{
struct pios_internal_flash_dev *flash_dev;
flash_dev = (struct pios_internal_flash_dev *)pios_malloc(sizeof(*flash_dev));
if (!flash_dev) {
return NULL;
}
flash_dev->magic = PIOS_INTERNAL_FLASH_DEV_MAGIC;
return flash_dev;
}
#else
static struct pios_internal_flash_dev pios_internal_flash_devs[PIOS_INTERNAL_FLASH_MAX_DEVS];
static uint8_t pios_internal_flash_num_devs;
static struct pios_internal_flash_dev *PIOS_Flash_Internal_alloc(void)
{
struct pios_internal_flash_dev *flash_dev;
if (pios_internal_flash_num_devs >= PIOS_INTERNAL_FLASH_MAX_DEVS) {
return NULL;
}
flash_dev = &pios_internal_flash_devs[pios_internal_flash_num_devs++];
flash_dev->magic = PIOS_INTERNAL_FLASH_DEV_MAGIC;
return flash_dev;
}
#endif /* defined(PIOS_INCLUDE_FREERTOS) */
int32_t PIOS_Flash_Internal_Init(uintptr_t *flash_id, __attribute__((unused)) const struct pios_flash_internal_cfg *cfg)
{
struct pios_internal_flash_dev *flash_dev;
flash_dev = PIOS_Flash_Internal_alloc();
if (flash_dev == NULL) {
return -1;
}
#if defined(PIOS_INCLUDE_FREERTOS)
flash_dev->transaction_lock = xSemaphoreCreateMutex();
#endif /* defined(PIOS_INCLUDE_FREERTOS) */
*flash_id = (uintptr_t)flash_dev;
return 0;
}
/**********************************
*
* Provide a PIOS flash driver API
*
*********************************/
#include "pios_flash.h"
static int32_t PIOS_Flash_Internal_StartTransaction(uintptr_t flash_id)
{
struct pios_internal_flash_dev *flash_dev = (struct pios_internal_flash_dev *)flash_id;
if (!PIOS_Flash_Internal_Validate(flash_dev)) {
return -1;
}
#if defined(PIOS_INCLUDE_FREERTOS)
if (xSemaphoreTake(flash_dev->transaction_lock, portMAX_DELAY) != pdTRUE) {
return -2;
}
#endif /* defined(PIOS_INCLUDE_FREERTOS) */
/* Unlock the internal flash so we can write to it */
FLASH_Unlock();
return 0;
}
static int32_t PIOS_Flash_Internal_EndTransaction(uintptr_t flash_id)
{
struct pios_internal_flash_dev *flash_dev = (struct pios_internal_flash_dev *)flash_id;
if (!PIOS_Flash_Internal_Validate(flash_dev)) {
return -1;
}
#if defined(PIOS_INCLUDE_FREERTOS)
if (xSemaphoreGive(flash_dev->transaction_lock) != pdTRUE) {
return -2;
}
#endif /* defined(PIOS_INCLUDE_FREERTOS) */
/* Lock the internal flash again so we can no longer write to it */
FLASH_Lock();
return 0;
}
static int32_t PIOS_Flash_Internal_EraseSector(uintptr_t flash_id, uint32_t addr)
{
struct pios_internal_flash_dev *flash_dev = (struct pios_internal_flash_dev *)flash_id;
if (!PIOS_Flash_Internal_Validate(flash_dev)) {
return -1;
}
uint8_t sector_number;
uint32_t sector_start;
uint32_t sector_size;
if (!PIOS_Flash_Internal_GetSectorInfo(addr,
&sector_number,
&sector_start,
&sector_size)) {
/* We're asking for an invalid flash address */
return -2;
}
if (FLASH_ErasePage(sector_start) != FLASH_COMPLETE) {
return -3;
}
return 0;
}
static int32_t PIOS_Flash_Internal_WriteData(uintptr_t flash_id, uint32_t addr, uint8_t *data, uint16_t len)
{
PIOS_Assert(data);
struct pios_internal_flash_dev *flash_dev = (struct pios_internal_flash_dev *)flash_id;
if (!PIOS_Flash_Internal_Validate(flash_dev)) {
return -1;
}
uint8_t sector_number;
uint32_t sector_start;
uint32_t sector_size;
uint32_t hword_data;
uint32_t offset;
/* Ensure that the base address is in a valid sector */
if (!PIOS_Flash_Internal_GetSectorInfo(addr,
&sector_number,
&sector_start,
&sector_size)) {
/* We're asking for an invalid flash address */
return -2;
}
/* Ensure that the entire write occurs within the same sector */
if ((uintptr_t)addr + len > sector_start + sector_size) {
/* Write crosses the end of the sector */
return -3;
}
/* Write the data */
uint32_t temp_addr = addr;
uint16_t numberOfhWords = len / 2;
uint16_t x = 0;
FLASH_Status status;
for (x = 0; x < numberOfhWords; ++x) {
offset = 2 * x;
hword_data = (data[offset + 1] << 8) | data[offset];
if (hword_data != *(uint16_t *)(temp_addr + offset)) {
status = FLASH_ProgramHalfWord(temp_addr + offset, hword_data);
} else {
status = FLASH_COMPLETE;
}
PIOS_Assert(status == FLASH_COMPLETE);
}
uint16_t mod = len % 2;
if (mod == 1) {
offset = 2 * x;
hword_data = 0xFF00 | data[offset];
if (hword_data != *(uint16_t *)(temp_addr + offset)) {
status = FLASH_ProgramHalfWord(temp_addr + offset, hword_data);
} else {
status = FLASH_COMPLETE;
}
PIOS_Assert(status == FLASH_COMPLETE);
}
return 0;
}
static int32_t PIOS_Flash_Internal_ReadData(uintptr_t flash_id, uint32_t addr, uint8_t *data, uint16_t len)
{
PIOS_Assert(data);
struct pios_internal_flash_dev *flash_dev = (struct pios_internal_flash_dev *)flash_id;
if (!PIOS_Flash_Internal_Validate(flash_dev)) {
return -1;
}
uint8_t sector_number;
uint32_t sector_start;
uint32_t sector_size;
/* Ensure that the base address is in a valid sector */
if (!PIOS_Flash_Internal_GetSectorInfo(addr,
&sector_number,
&sector_start,
&sector_size)) {
/* We're asking for an invalid flash address */
return -2;
}
/* Ensure that the entire read occurs within the same sector */
if ((uintptr_t)addr + len > sector_start + sector_size) {
/* Read crosses the end of the sector */
return -3;
}
/* Read the data into the buffer directly */
memcpy(data, (void *)addr, len);
return 0;
}
/* Provide a flash driver to external drivers */
const struct pios_flash_driver pios_internal_flash_driver = {
.start_transaction = PIOS_Flash_Internal_StartTransaction,
.end_transaction = PIOS_Flash_Internal_EndTransaction,
.erase_sector = PIOS_Flash_Internal_EraseSector,
.write_data = PIOS_Flash_Internal_WriteData,
.read_data = PIOS_Flash_Internal_ReadData,
};
#endif /* PIOS_INCLUDE_FLASH_INTERNAL */

View File

@ -0,0 +1,170 @@
/**
******************************************************************************
* @addtogroup PIOS PIOS Core hardware abstraction layer
* @{
* @addtogroup PIOS_GPIO GPIO Functions
* @brief STM32 Hardware GPIO handling code
* @{
*
* @file pios_gpio.c
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
* @brief GPIO functions, init, toggle, on & off.
* @see The GNU Public License (GPL) Version 3
*
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "pios.h"
#ifdef PIOS_INCLUDE_GPIO
#include <pios_gpio_priv.h>
/**
* Initialises all the GPIO's
*/
int32_t PIOS_GPIO_Init(uint32_t *gpios_dev_id, const struct pios_gpio_cfg *cfg)
{
PIOS_Assert(cfg);
*gpios_dev_id = (uint32_t)cfg;
for (uint8_t i = 0; i < cfg->num_gpios; i++) {
const struct pios_gpio *gpio = &(cfg->gpios[i]);
/* Enable the peripheral clock for the GPIO */
switch ((uint32_t)gpio->pin.gpio) {
case (uint32_t)GPIOA:
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
break;
case (uint32_t)GPIOB:
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
break;
case (uint32_t)GPIOC:
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);
break;
case (uint32_t)GPIOD:
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOD, ENABLE);
break;
case (uint32_t)GPIOE:
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOE, ENABLE);
break;
case (uint32_t)GPIOF:
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOF, ENABLE);
break;
default:
PIOS_Assert(0);
break;
}
if (gpio->remap) {
GPIO_PinAFConfig(gpio->pin.gpio, gpio->pin.init.GPIO_Pin, gpio->remap);
}
GPIO_Init(gpio->pin.gpio, &((struct pios_gpio *)gpio)->pin.init);
PIOS_GPIO_Off(*gpios_dev_id, i);
}
return 0;
}
/**
* Turn on GPIO
* \param[in] GPIO GPIO id
*/
void PIOS_GPIO_On(uint32_t gpios_dev_id, uint8_t gpio_id)
{
const struct pios_gpio_cfg *gpio_cfg = (const struct pios_gpio_cfg *)gpios_dev_id;
PIOS_Assert(gpio_cfg);
if (gpio_id >= gpio_cfg->num_gpios) {
/* GPIO index out of range */
return;
}
const struct pios_gpio *gpio = &(gpio_cfg->gpios[gpio_id]);
if (gpio->active_low) {
GPIO_ResetBits(gpio->pin.gpio, gpio->pin.init.GPIO_Pin);
} else {
GPIO_SetBits(gpio->pin.gpio, gpio->pin.init.GPIO_Pin);
}
}
/**
* Turn off GPIO
* \param[in] GPIO GPIO id
*/
void PIOS_GPIO_Off(uint32_t gpios_dev_id, uint8_t gpio_id)
{
const struct pios_gpio_cfg *gpio_cfg = (const struct pios_gpio_cfg *)gpios_dev_id;
PIOS_Assert(gpio_cfg);
if (gpio_id >= gpio_cfg->num_gpios) {
/* GPIO index out of range */
return;
}
const struct pios_gpio *gpio = &(gpio_cfg->gpios[gpio_id]);
if (gpio->active_low) {
GPIO_SetBits(gpio->pin.gpio, gpio->pin.init.GPIO_Pin);
} else {
GPIO_ResetBits(gpio->pin.gpio, gpio->pin.init.GPIO_Pin);
}
}
/**
* Toggle GPIO on/off
* \param[in] GPIO GPIO id
*/
void PIOS_GPIO_Toggle(uint32_t gpios_dev_id, uint8_t gpio_id)
{
const struct pios_gpio_cfg *gpio_cfg = (const struct pios_gpio_cfg *)gpios_dev_id;
PIOS_Assert(gpio_cfg);
if (gpio_id >= gpio_cfg->num_gpios) {
/* GPIO index out of range */
return;
}
const struct pios_gpio *gpio = &(gpio_cfg->gpios[gpio_id]);
if (GPIO_ReadOutputDataBit(gpio->pin.gpio, gpio->pin.init.GPIO_Pin) == Bit_SET) {
if (gpio->active_low) {
PIOS_GPIO_On(gpios_dev_id, gpio_id);
} else {
PIOS_GPIO_Off(gpios_dev_id, gpio_id);
}
} else {
if (gpio->active_low) {
PIOS_GPIO_Off(gpios_dev_id, gpio_id);
} else {
PIOS_GPIO_On(gpios_dev_id, gpio_id);
}
}
}
#endif /* PIOS_INCLUDE_GPIO */
/**
* @}
* @}
*/

View File

@ -0,0 +1,921 @@
/**
******************************************************************************
* @addtogroup PIOS PIOS Core hardware abstraction layer
* @{
* @addtogroup PIOS_I2C I2C Functions
* @brief STM32F30x Hardware dependent I2C functionality
* @{
*
* @file pios_i2c.c
* @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017.
* dRonin, http://dronin.org, Copyright (C) 2016
* Tau Labs, http://taulabs.org, Copyright (C) 2012-2014
* The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
* @brief I2C Enable/Disable routines
* @see The GNU Public License (GPL) Version 3
*
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* Project Includes */
#include "pios.h"
#if defined(PIOS_INCLUDE_I2C)
#include <pios_i2c_priv.h>
enum i2c_adapter_state {
I2C_STATE_FSM_FAULT = 0, /* Must be zero so undefined transitions land here */
I2C_STATE_BUS_ERROR,
I2C_STATE_STOPPED,
I2C_STATE_STOPPING,
I2C_STATE_STARTING,
I2C_STATE_R_MORE_TXN_ADDR,
I2C_STATE_R_MORE_TXN_PRE_ONE,
I2C_STATE_R_MORE_TXN_PRE_FIRST,
I2C_STATE_R_MORE_TXN_PRE_MIDDLE,
I2C_STATE_R_MORE_TXN_PRE_LAST,
I2C_STATE_R_MORE_TXN_POST_LAST,
I2C_STATE_R_LAST_TXN_ADDR,
I2C_STATE_R_LAST_TXN_PRE_ONE,
I2C_STATE_R_LAST_TXN_PRE_FIRST,
I2C_STATE_R_LAST_TXN_PRE_MIDDLE,
I2C_STATE_R_LAST_TXN_PRE_LAST,
I2C_STATE_R_LAST_TXN_POST_LAST,
I2C_STATE_W_MORE_TXN_ADDR,
I2C_STATE_W_MORE_TXN_MIDDLE,
I2C_STATE_W_MORE_TXN_LAST,
I2C_STATE_W_LAST_TXN_ADDR,
I2C_STATE_W_LAST_TXN_MIDDLE,
I2C_STATE_W_LAST_TXN_LAST,
I2C_STATE_NACK,
I2C_STATE_NUM_STATES /* Must be last */
};
enum i2c_adapter_event {
I2C_EVENT_START,
I2C_EVENT_RECEIVER_BUFFER_NOT_EMPTY,
I2C_EVENT_TRANSMIT_BUFFER_EMPTY,
I2C_EVENT_TRANSFER_COMPLETE,
I2C_EVENT_STOP,
I2C_EVENT_NACK,
I2C_EVENT_BUS_ERROR,
I2C_EVENT_STOPPED,
I2C_EVENT_AUTO,
I2C_EVENT_NUM_EVENTS /* Must be last */
};
/* dirty hack to keep compatible with enum in pios_i2c_priv.h */
#define I2C_STATE_WRITE_BYTE I2C_STATE_W_MORE_TXN_ADDR
#define I2C_STATE_READ_BYTE I2C_STATE_W_MORE_TXN_MIDDLE
#define I2C_STATE_TRANSFER_COMPLETE I2C_STATE_W_MORE_TXN_LAST
// #define I2C_HALT_ON_ERRORS
#if defined(PIOS_I2C_DIAGNOSTICS)
static struct pios_i2c_fault_history i2c_adapter_fault_history;
static volatile uint32_t i2c_evirq_history[I2C_LOG_DEPTH];
static volatile uint8_t i2c_evirq_history_pointer;
static volatile uint32_t i2c_erirq_history[I2C_LOG_DEPTH];
static volatile uint8_t i2c_erirq_history_pointer;
static volatile uint8_t i2c_state_history[I2C_LOG_DEPTH];
static volatile uint8_t i2c_state_history_pointer;
static volatile uint8_t i2c_state_event_history[I2C_LOG_DEPTH];
static volatile uint8_t i2c_state_event_history_pointer;
static uint32_t i2c_fsm_fault_count;
static uint32_t i2c_bad_event_counter;
static uint32_t i2c_error_interrupt_counter;
static uint32_t i2c_nack_counter;
static uint32_t i2c_timeout_counter;
#endif
static void go_fsm_fault(struct pios_i2c_adapter *i2c_adapter, bool *woken);
static void go_bus_error(struct pios_i2c_adapter *i2c_adapter, bool *woken);
static void go_stopped(struct pios_i2c_adapter *i2c_adapter, bool *woken);
static void go_starting(struct pios_i2c_adapter *i2c_adapter, bool *woken);
static void go_write_byte(struct pios_i2c_adapter *i2c_adapter, bool *woken);
static void go_read_byte(struct pios_i2c_adapter *i2c_adapter, bool *woken);
static void go_transfer_complete(struct pios_i2c_adapter *i2c_adapter, bool *woken);
static void go_nack(struct pios_i2c_adapter *i2c_adapter, bool *woken);
struct i2c_adapter_transition {
void (*entry_fn)(struct pios_i2c_adapter *i2c_adapter, bool *woken);
enum i2c_adapter_state next_state[I2C_EVENT_NUM_EVENTS];
};
static void i2c_adapter_process_auto(struct pios_i2c_adapter *i2c_adapter, bool *woken);
static void i2c_adapter_inject_event(struct pios_i2c_adapter *i2c_adapter, enum i2c_adapter_event event, bool *woken);
static void i2c_adapter_fsm_init(struct pios_i2c_adapter *i2c_adapter);
static void i2c_adapter_reset_bus(struct pios_i2c_adapter *i2c_adapter);
static bool i2c_adapter_callback_handler(struct pios_i2c_adapter *i2c_adapter, bool *woken);
#if defined(PIOS_I2C_DIAGNOSTICS)
static void i2c_adapter_log_fault(struct pios_i2c_adapter *i2c_adapter, enum pios_i2c_error_type type);
#endif
static const struct i2c_adapter_transition i2c_adapter_transitions[I2C_STATE_NUM_STATES] = {
[I2C_STATE_FSM_FAULT] = {
.entry_fn = go_fsm_fault,
.next_state = {
[I2C_EVENT_AUTO] = I2C_STATE_STOPPED,
},
},
[I2C_STATE_BUS_ERROR] = {
.entry_fn = go_bus_error,
.next_state = {
[I2C_EVENT_AUTO] = I2C_STATE_STOPPED,
},
},
[I2C_STATE_STOPPED] = {
.entry_fn = go_stopped,
.next_state = {
[I2C_EVENT_START] = I2C_STATE_STARTING,
[I2C_EVENT_BUS_ERROR] = I2C_STATE_BUS_ERROR,
},
},
[I2C_STATE_STARTING] = {
.entry_fn = go_starting,
.next_state = {
[I2C_EVENT_TRANSMIT_BUFFER_EMPTY] = I2C_STATE_WRITE_BYTE,
[I2C_EVENT_RECEIVER_BUFFER_NOT_EMPTY] = I2C_STATE_READ_BYTE,
[I2C_EVENT_NACK] = I2C_STATE_NACK,
[I2C_EVENT_BUS_ERROR] = I2C_STATE_BUS_ERROR,
},
},
[I2C_STATE_WRITE_BYTE] = {
.entry_fn = go_write_byte,
.next_state = {
[I2C_EVENT_TRANSMIT_BUFFER_EMPTY] = I2C_STATE_WRITE_BYTE,
[I2C_EVENT_RECEIVER_BUFFER_NOT_EMPTY] = I2C_STATE_READ_BYTE,
[I2C_EVENT_TRANSFER_COMPLETE] = I2C_STATE_TRANSFER_COMPLETE,
[I2C_EVENT_STOP] = I2C_STATE_STOPPED,
[I2C_EVENT_BUS_ERROR] = I2C_STATE_BUS_ERROR,
},
},
[I2C_STATE_READ_BYTE] = {
.entry_fn = go_read_byte,
.next_state = {
[I2C_EVENT_TRANSMIT_BUFFER_EMPTY] = I2C_STATE_WRITE_BYTE,
[I2C_EVENT_RECEIVER_BUFFER_NOT_EMPTY] = I2C_STATE_READ_BYTE,
[I2C_EVENT_TRANSFER_COMPLETE] = I2C_STATE_TRANSFER_COMPLETE,
[I2C_EVENT_STOP] = I2C_STATE_STOPPED,
[I2C_EVENT_BUS_ERROR] = I2C_STATE_BUS_ERROR,
},
},
[I2C_STATE_TRANSFER_COMPLETE] = {
.entry_fn = go_transfer_complete,
.next_state = {
[I2C_EVENT_AUTO] = I2C_STATE_STARTING,
[I2C_EVENT_BUS_ERROR] = I2C_STATE_BUS_ERROR,
},
},
[I2C_STATE_NACK] = {
.entry_fn = go_nack,
.next_state = {
[I2C_EVENT_AUTO] = I2C_STATE_STOPPED,
},
},
};
static void go_fsm_fault(struct pios_i2c_adapter *i2c_adapter, __attribute__((unused)) bool *woken)
{
#if defined(I2C_HALT_ON_ERRORS)
PIOS_DEBUG_Assert(0);
#endif
/* Note that this transfer has hit a bus error */
i2c_adapter->bus_error = true;
i2c_adapter_reset_bus(i2c_adapter);
}
static void go_bus_error(struct pios_i2c_adapter *i2c_adapter, __attribute__((unused)) bool *woken)
{
/* Note that this transfer has hit a bus error */
i2c_adapter->bus_error = true;
i2c_adapter_reset_bus(i2c_adapter);
}
static void go_stopped(struct pios_i2c_adapter *i2c_adapter, bool *woken)
{
I2C_ITConfig(i2c_adapter->cfg->regs, I2C_IT_ERRI | I2C_IT_TCI | I2C_IT_NACKI | I2C_IT_RXI | I2C_IT_STOPI | I2C_IT_TXI, DISABLE);
if (i2c_adapter->callback) {
i2c_adapter_callback_handler(i2c_adapter, woken);
} else {
#ifdef PIOS_INCLUDE_FREERTOS
signed portBASE_TYPE pxHigherPriorityTaskWoken = pdFALSE;
if (xSemaphoreGiveFromISR(i2c_adapter->sem_ready, &pxHigherPriorityTaskWoken) != pdTRUE) {
#if defined(I2C_HALT_ON_ERRORS)
PIOS_DEBUG_Assert(0);
#endif
}
if (pxHigherPriorityTaskWoken == pdTRUE) {
*woken = true;
}
#endif /* PIOS_INCLUDE_FREERTOS */
}
}
static void go_starting(struct pios_i2c_adapter *i2c_adapter, __attribute__((unused)) bool *woken)
{
PIOS_DEBUG_Assert(i2c_adapter->active_txn);
PIOS_DEBUG_Assert(i2c_adapter->active_txn <= i2c_adapter->last_txn);
PIOS_DEBUG_Assert(i2c_adapter->active_txn->len <= 255); // FIXME: implement this using TCR
i2c_adapter->active_byte = &(i2c_adapter->active_txn->buf[0]);
i2c_adapter->last_byte = &(i2c_adapter->active_txn->buf[i2c_adapter->active_txn->len - 1]);
I2C_ITConfig(i2c_adapter->cfg->regs, I2C_IT_ERRI | I2C_IT_TCI | I2C_IT_NACKI | I2C_IT_RXI | I2C_IT_STOPI | I2C_IT_TXI, ENABLE);
I2C_TransferHandling(
i2c_adapter->cfg->regs,
(i2c_adapter->active_txn->addr << 1),
i2c_adapter->active_txn->len,
i2c_adapter->active_txn == i2c_adapter->last_txn ? I2C_AutoEnd_Mode : I2C_SoftEnd_Mode,
i2c_adapter->active_txn->rw == PIOS_I2C_TXN_WRITE ? I2C_Generate_Start_Write : I2C_Generate_Start_Read);
}
static void go_write_byte(struct pios_i2c_adapter *i2c_adapter, __attribute__((unused)) bool *woken)
{
PIOS_DEBUG_Assert(i2c_adapter->active_txn);
PIOS_DEBUG_Assert(i2c_adapter->active_txn <= i2c_adapter->last_txn);
I2C_SendData(i2c_adapter->cfg->regs, *(i2c_adapter->active_byte));
/* Move to the next byte */
i2c_adapter->active_byte++;
PIOS_DEBUG_Assert(i2c_adapter->active_byte <= i2c_adapter->last_byte);
}
static void go_read_byte(struct pios_i2c_adapter *i2c_adapter, __attribute__((unused)) bool *woken)
{
PIOS_DEBUG_Assert(i2c_adapter->active_txn);
PIOS_DEBUG_Assert(i2c_adapter->active_txn <= i2c_adapter->last_txn);
*(i2c_adapter->active_byte) = I2C_ReceiveData(i2c_adapter->cfg->regs);
/* Move to the next byte */
i2c_adapter->active_byte++;
PIOS_DEBUG_Assert(i2c_adapter->active_byte <= i2c_adapter->last_byte);
}
static void go_transfer_complete(struct pios_i2c_adapter *i2c_adapter, __attribute__((unused)) bool *woken)
{
/* Move to the next transaction */
i2c_adapter->active_txn++;
PIOS_DEBUG_Assert(i2c_adapter->active_txn <= i2c_adapter->last_txn);
}
static void go_nack(struct pios_i2c_adapter *i2c_adapter, __attribute__((unused)) bool *woken)
{
i2c_adapter->nack = true;
I2C_ITConfig(i2c_adapter->cfg->regs, I2C_IT_ERRI | I2C_IT_TCI | I2C_IT_NACKI | I2C_IT_RXI | I2C_IT_STOPI | I2C_IT_TXI, DISABLE);
I2C_AcknowledgeConfig(i2c_adapter->cfg->regs, DISABLE);
I2C_GenerateSTOP(i2c_adapter->cfg->regs, ENABLE);
}
static void i2c_adapter_inject_event(struct pios_i2c_adapter *i2c_adapter, enum i2c_adapter_event event, bool *woken)
{
#if defined(PIOS_I2C_DIAGNOSTICS)
i2c_state_event_history[i2c_state_event_history_pointer] = event;
i2c_state_event_history_pointer = (i2c_state_event_history_pointer + 1) % I2C_LOG_DEPTH;
i2c_state_history[i2c_state_history_pointer] = i2c_adapter->curr_state;
i2c_state_history_pointer = (i2c_state_history_pointer + 1) % I2C_LOG_DEPTH;
if (i2c_adapter_transitions[i2c_adapter->curr_state].next_state[event] == I2C_STATE_FSM_FAULT) {
i2c_adapter_log_fault(i2c_adapter, PIOS_I2C_ERROR_FSM);
}
#endif
/*
* Move to the next state
*
* This is done prior to calling the new state's entry function to
* guarantee that the entry function never depends on the previous
* state. This way, it cannot ever know what the previous state was.
*/
enum i2c_adapter_state prev_state = i2c_adapter->curr_state;
if (prev_state) {
;
}
i2c_adapter->curr_state = i2c_adapter_transitions[i2c_adapter->curr_state].next_state[event];
/* Call the entry function (if any) for the next state. */
if (i2c_adapter_transitions[i2c_adapter->curr_state].entry_fn) {
i2c_adapter_transitions[i2c_adapter->curr_state].entry_fn(i2c_adapter, woken);
}
/* Process any AUTO transitions in the FSM */
i2c_adapter_process_auto(i2c_adapter, woken);
}
static void i2c_adapter_process_auto(struct pios_i2c_adapter *i2c_adapter, bool *woken)
{
enum i2c_adapter_state prev_state = i2c_adapter->curr_state;
if (prev_state) {
;
}
while (i2c_adapter_transitions[i2c_adapter->curr_state].next_state[I2C_EVENT_AUTO]) {
i2c_adapter->curr_state = i2c_adapter_transitions[i2c_adapter->curr_state].next_state[I2C_EVENT_AUTO];
/* Call the entry function (if any) for the next state. */
if (i2c_adapter_transitions[i2c_adapter->curr_state].entry_fn) {
i2c_adapter_transitions[i2c_adapter->curr_state].entry_fn(i2c_adapter, woken);
}
}
}
static void i2c_adapter_fsm_init(struct pios_i2c_adapter *i2c_adapter)
{
i2c_adapter_reset_bus(i2c_adapter);
i2c_adapter->curr_state = I2C_STATE_STOPPED;
}
static void i2c_adapter_reset_bus(struct pios_i2c_adapter *i2c_adapter)
{
uint8_t retry_count = 0;
uint8_t retry_count_clk = 0;
static const uint8_t MAX_I2C_RETRY_COUNT = 10;
/* Reset the I2C block */
I2C_DeInit(i2c_adapter->cfg->regs);
/* Make sure the bus is free by clocking it until any slaves release the bus. */
GPIO_InitTypeDef scl_gpio_init;
scl_gpio_init = i2c_adapter->cfg->scl.init;
scl_gpio_init.GPIO_Mode = GPIO_Mode_OUT;
GPIO_SetBits(i2c_adapter->cfg->scl.gpio, i2c_adapter->cfg->scl.init.GPIO_Pin);
GPIO_Init(i2c_adapter->cfg->scl.gpio, &scl_gpio_init);
GPIO_InitTypeDef sda_gpio_init;
sda_gpio_init = i2c_adapter->cfg->sda.init;
sda_gpio_init.GPIO_Mode = GPIO_Mode_OUT;
GPIO_SetBits(i2c_adapter->cfg->sda.gpio, i2c_adapter->cfg->sda.init.GPIO_Pin);
GPIO_Init(i2c_adapter->cfg->sda.gpio, &sda_gpio_init);
/* Check SDA line to determine if slave is asserting bus and clock out if so, this may */
/* have to be repeated (due to further bus errors) but better than clocking 0xFF into an */
/* ESC */
retry_count_clk = 0;
while (GPIO_ReadInputDataBit(i2c_adapter->cfg->sda.gpio, i2c_adapter->cfg->sda.init.GPIO_Pin) == Bit_RESET && (retry_count_clk++ < MAX_I2C_RETRY_COUNT)) {
retry_count = 0;
/* Set clock high and wait for any clock stretching to finish. */
GPIO_SetBits(i2c_adapter->cfg->scl.gpio, i2c_adapter->cfg->scl.init.GPIO_Pin);
while (GPIO_ReadInputDataBit(i2c_adapter->cfg->scl.gpio, i2c_adapter->cfg->scl.init.GPIO_Pin) == Bit_RESET && (retry_count++ < MAX_I2C_RETRY_COUNT)) {
PIOS_DELAY_WaituS(1);
}
PIOS_DELAY_WaituS(2);
/* Set clock low */
GPIO_ResetBits(i2c_adapter->cfg->scl.gpio, i2c_adapter->cfg->scl.init.GPIO_Pin);
PIOS_DELAY_WaituS(2);
/* Clock high again */
GPIO_SetBits(i2c_adapter->cfg->scl.gpio, i2c_adapter->cfg->scl.init.GPIO_Pin);
PIOS_DELAY_WaituS(2);
}
/* Generate a start then stop condition */
GPIO_SetBits(i2c_adapter->cfg->scl.gpio, i2c_adapter->cfg->scl.init.GPIO_Pin);
PIOS_DELAY_WaituS(2);
GPIO_ResetBits(i2c_adapter->cfg->sda.gpio, i2c_adapter->cfg->sda.init.GPIO_Pin);
PIOS_DELAY_WaituS(2);
GPIO_ResetBits(i2c_adapter->cfg->sda.gpio, i2c_adapter->cfg->sda.init.GPIO_Pin);
PIOS_DELAY_WaituS(2);
/* Set data and clock high and wait for any clock stretching to finish. */
GPIO_SetBits(i2c_adapter->cfg->sda.gpio, i2c_adapter->cfg->sda.init.GPIO_Pin);
GPIO_SetBits(i2c_adapter->cfg->scl.gpio, i2c_adapter->cfg->scl.init.GPIO_Pin);
retry_count = 0;
while (GPIO_ReadInputDataBit(i2c_adapter->cfg->scl.gpio, i2c_adapter->cfg->scl.init.GPIO_Pin) == Bit_RESET && (retry_count++ < MAX_I2C_RETRY_COUNT)) {
PIOS_DELAY_WaituS(1);
}
/* Wait for data to be high */
retry_count = 0;
while (GPIO_ReadInputDataBit(i2c_adapter->cfg->sda.gpio, i2c_adapter->cfg->sda.init.GPIO_Pin) != Bit_SET && (retry_count++ < MAX_I2C_RETRY_COUNT)) {
PIOS_DELAY_WaituS(1);
}
/* Bus signals are guaranteed to be high (ie. free) after this point */
/* Initialize the GPIO pins to the peripheral function */
if (i2c_adapter->cfg->remapSCL) {
GPIO_PinAFConfig(i2c_adapter->cfg->scl.gpio,
__builtin_ctz(i2c_adapter->cfg->scl.init.GPIO_Pin),
i2c_adapter->cfg->remapSCL);
}
if (i2c_adapter->cfg->remapSDA) {
GPIO_PinAFConfig(i2c_adapter->cfg->sda.gpio,
__builtin_ctz(i2c_adapter->cfg->sda.init.GPIO_Pin),
i2c_adapter->cfg->remapSDA);
}
GPIO_Init(i2c_adapter->cfg->scl.gpio, (GPIO_InitTypeDef *)&(i2c_adapter->cfg->scl.init)); // Struct is const, function signature not
GPIO_Init(i2c_adapter->cfg->sda.gpio, (GPIO_InitTypeDef *)&(i2c_adapter->cfg->sda.init));
RCC_I2CCLKConfig(i2c_adapter->cfg->regs == I2C2 ? RCC_I2C2CLK_SYSCLK : RCC_I2C1CLK_SYSCLK);
/* Reset the I2C block */
I2C_DeInit(i2c_adapter->cfg->regs);
/* Initialize the I2C block */
I2C_Init(i2c_adapter->cfg->regs, (I2C_InitTypeDef *)&(i2c_adapter->cfg->init));
/* Enable the I2C block */
I2C_Cmd(i2c_adapter->cfg->regs, ENABLE);
if (I2C_GetFlagStatus(i2c_adapter->cfg->regs, I2C_FLAG_BUSY)) {
I2C_SoftwareResetCmd(i2c_adapter->cfg->regs);
}
}
/**
* Logs the last N state transitions and N IRQ events due to
* an error condition
* \param[in] i2c the adapter number to log an event for
*/
#if defined(PIOS_I2C_DIAGNOSTICS)
void i2c_adapter_log_fault(__attribute__((unused)) struct pios_i2c_adapter *i2c_adapter, enum pios_i2c_error_type type)
{
i2c_adapter_fault_history.type = type;
for (uint8_t i = 0; i < I2C_LOG_DEPTH; i++) {
i2c_adapter_fault_history.evirq[i] =
i2c_evirq_history[(I2C_LOG_DEPTH + i2c_evirq_history_pointer - 1 - i) % I2C_LOG_DEPTH];
i2c_adapter_fault_history.erirq[i] =
i2c_erirq_history[(I2C_LOG_DEPTH + i2c_erirq_history_pointer - 1 - i) % I2C_LOG_DEPTH];
i2c_adapter_fault_history.event[i] =
i2c_state_event_history[(I2C_LOG_DEPTH + i2c_state_event_history_pointer - 1 - i) % I2C_LOG_DEPTH];
i2c_adapter_fault_history.state[i] =
i2c_state_history[(I2C_LOG_DEPTH + i2c_state_history_pointer - 1 - i) % I2C_LOG_DEPTH];
}
switch (type) {
case PIOS_I2C_ERROR_EVENT:
i2c_bad_event_counter++;
break;
case PIOS_I2C_ERROR_FSM:
i2c_fsm_fault_count++;
break;
case PIOS_I2C_ERROR_INTERRUPT:
i2c_error_interrupt_counter++;
break;
}
}
#endif /* if defined(PIOS_I2C_DIAGNOSTICS) */
/**
* Logs the last N state transitions and N IRQ events due to
* an error condition
* \param[out] data address where to copy the pios_i2c_fault_history structure to
* \param[out] counts three uint16 that receive the bad event, fsm, and error irq
* counts
*/
void PIOS_I2C_GetDiagnostics(struct pios_i2c_fault_history *data, uint8_t *counts)
{
#if defined(PIOS_I2C_DIAGNOSTICS)
memcpy(data, &i2c_adapter_fault_history, sizeof(i2c_adapter_fault_history));
counts[PIOS_I2C_BAD_EVENT_COUNTER] = i2c_bad_event_counter;
counts[PIOS_I2C_FSM_FAULT_COUNT] = i2c_fsm_fault_count;
counts[PIOS_I2C_ERROR_INTERRUPT_COUNTER] = i2c_error_interrupt_counter;
counts[PIOS_I2C_NACK_COUNTER] = i2c_nack_counter;
counts[PIOS_I2C_TIMEOUT_COUNTER] = i2c_timeout_counter;
#else
struct pios_i2c_fault_history i2c_adapter_fault_history;
i2c_adapter_fault_history.type = PIOS_I2C_ERROR_EVENT;
memcpy(data, &i2c_adapter_fault_history, sizeof(i2c_adapter_fault_history));
memset(counts, 0, sizeof(*counts) * PIOS_I2C_ERROR_COUNT_NUMELEM);
#endif
}
static bool PIOS_I2C_validate(struct pios_i2c_adapter *i2c_adapter)
{
return i2c_adapter->magic == PIOS_I2C_DEV_MAGIC;
}
#if defined(PIOS_INCLUDE_FREERTOS)
static struct pios_i2c_adapter *PIOS_I2C_alloc(void)
{
struct pios_i2c_adapter *i2c_adapter;
i2c_adapter = (struct pios_i2c_adapter *)pios_malloc(sizeof(*i2c_adapter));
if (!i2c_adapter) {
return NULL;
}
i2c_adapter->magic = PIOS_I2C_DEV_MAGIC;
return i2c_adapter;
}
#else
static struct pios_i2c_adapter pios_i2c_adapters[PIOS_I2C_MAX_DEVS];
static uint8_t pios_i2c_num_adapters;
static struct pios_i2c_adapter *PIOS_I2C_alloc(void)
{
struct pios_i2c_adapter *i2c_adapter;
if (pios_i2c_num_adapters >= PIOS_I2C_MAX_DEVS) {
return NULL;
}
i2c_adapter = &pios_i2c_adapters[pios_i2c_num_adapters++];
i2c_adapter->magic = PIOS_I2C_DEV_MAGIC;
return i2c_adapter;
}
#endif /* if defined(PIOS_INCLUDE_CHIBIOS) && 0 */
/**
* Initializes IIC driver
* \param[in] mode currently only mode 0 supported
* \return < 0 if initialisation failed
*/
int32_t PIOS_I2C_Init(uint32_t *i2c_id, const struct pios_i2c_adapter_cfg *cfg)
{
PIOS_DEBUG_Assert(i2c_id);
PIOS_DEBUG_Assert(cfg);
struct pios_i2c_adapter *i2c_adapter;
i2c_adapter = (struct pios_i2c_adapter *)PIOS_I2C_alloc();
if (!i2c_adapter) {
goto out_fail;
}
/* Bind the configuration to the device instance */
i2c_adapter->cfg = cfg;
vSemaphoreCreateBinary(i2c_adapter->sem_ready);
i2c_adapter->sem_busy = xSemaphoreCreateMutex();
/* Initialize the state machine */
i2c_adapter_fsm_init(i2c_adapter);
*i2c_id = (uint32_t)i2c_adapter;
/* Configure and enable I2C interrupts */
NVIC_Init((NVIC_InitTypeDef *)&(i2c_adapter->cfg->event.init));
NVIC_Init((NVIC_InitTypeDef *)&(i2c_adapter->cfg->error.init));
/* No error */
return 0;
out_fail:
return -1;
}
int32_t PIOS_I2C_Transfer(uint32_t i2c_id, const struct pios_i2c_txn txn_list[], uint32_t num_txns)
{
// FIXME: only supports transfer sizes up to 255 bytes
struct pios_i2c_adapter *i2c_adapter = (struct pios_i2c_adapter *)i2c_id;
bool valid = PIOS_I2C_validate(i2c_adapter);
PIOS_Assert(valid)
PIOS_DEBUG_Assert(txn_list);
PIOS_DEBUG_Assert(num_txns);
bool semaphore_success = true;
#ifdef PIOS_INCLUDE_FREERTOS
/* Lock the bus */
portTickType timeout;
timeout = i2c_adapter->cfg->transfer_timeout_ms / portTICK_RATE_MS;
if (xSemaphoreTake(i2c_adapter->sem_busy, timeout) == pdFALSE) {
return -2;
}
#else
PIOS_IRQ_Disable();
if (i2c_adapter->busy) {
PIOS_IRQ_Enable();
return -2;
}
i2c_adapter->busy = 1;
PIOS_IRQ_Enable();
#endif /* PIOS_INCLUDE_FREERTOS */
PIOS_DEBUG_Assert(i2c_adapter->curr_state == I2C_STATE_STOPPED);
i2c_adapter->last_txn = &txn_list[num_txns - 1];
i2c_adapter->active_txn = &txn_list[0];
i2c_adapter->bus_error = false;
i2c_adapter->nack = false;
#ifdef PIOS_INCLUDE_FREERTOS
/* Make sure the done/ready semaphore is consumed before we start */
semaphore_success &= (xSemaphoreTake(i2c_adapter->sem_ready, timeout) == pdTRUE);
#endif
i2c_adapter->callback = NULL;
bool dummy = false;
i2c_adapter_inject_event(i2c_adapter, I2C_EVENT_START, &dummy);
/* Wait for the transfer to complete */
#ifdef PIOS_INCLUDE_FREERTOS
semaphore_success &= (xSemaphoreTake(i2c_adapter->sem_ready, timeout) == pdTRUE);
xSemaphoreGive(i2c_adapter->sem_ready);
#endif /* PIOS_INCLUDE_FREERTOS */
#ifdef PIOS_INCLUDE_FREERTOS
/* Unlock the bus */
xSemaphoreGive(i2c_adapter->sem_busy);
#if defined(PIOS_I2C_DIAGNOSTICS)
if (!semaphore_success) {
i2c_timeout_counter++;
}
#endif
#else
PIOS_IRQ_Disable();
i2c_adapter->busy = 0;
PIOS_IRQ_Enable();
#endif /* PIOS_INCLUDE_FREERTOS */
return !semaphore_success ? -2 :
i2c_adapter->bus_error ? -1 :
i2c_adapter->nack ? -3 :
0;
}
static int32_t PIOS_I2C_Transfer_Callback_Internal(struct pios_i2c_adapter *i2c_adapter, const struct pios_i2c_txn txn_list[], uint32_t num_txns, pios_i2c_callback callback)
{
PIOS_DEBUG_Assert(i2c_adapter->curr_state == I2C_STATE_STOPPED);
i2c_adapter->last_txn = &txn_list[num_txns - 1];
i2c_adapter->active_txn = &txn_list[0];
i2c_adapter->bus_error = false;
i2c_adapter->nack = false;
i2c_adapter->callback = callback;
// Estimate bytes of transmission. Per txns: 1 adress byte + length
i2c_adapter->transfer_timeout_ticks = num_txns;
for (uint32_t i = 0; i < num_txns; i++) {
i2c_adapter->transfer_timeout_ticks += txn_list[i].len;
}
// timeout if it takes eight times the expected time
i2c_adapter->transfer_timeout_ticks <<= 3;
bool dummy = false;
i2c_adapter_inject_event(i2c_adapter, I2C_EVENT_START, &dummy);
return 0;
}
int32_t PIOS_I2C_Transfer_Callback(uint32_t i2c_id, const struct pios_i2c_txn txn_list[], uint32_t num_txns, pios_i2c_callback callback)
{
// FIXME: only supports transfer sizes up to 255 bytes
struct pios_i2c_adapter *i2c_adapter = (struct pios_i2c_adapter *)i2c_id;
bool valid = PIOS_I2C_validate(i2c_adapter);
PIOS_Assert(valid)
PIOS_DEBUG_Assert(txn_list);
PIOS_DEBUG_Assert(num_txns);
#ifdef PIOS_INCLUDE_FREERTOS
/* Lock the bus */
portTickType timeout;
timeout = i2c_adapter->cfg->transfer_timeout_ms / portTICK_RATE_MS;
if (xSemaphoreTake(i2c_adapter->sem_busy, timeout) == pdFALSE) {
return -2;
}
#else
PIOS_IRQ_Disable();
if (i2c_adapter->busy) {
PIOS_IRQ_Enable();
return -2;
}
i2c_adapter->busy = 1;
PIOS_IRQ_Enable();
#endif /* PIOS_INCLUDE_FREERTOS */
return PIOS_I2C_Transfer_Callback_Internal(i2c_adapter, txn_list, num_txns, callback);
}
int32_t PIOS_I2C_Transfer_CallbackFromISR(uint32_t i2c_id, const struct pios_i2c_txn txn_list[], uint32_t num_txns, pios_i2c_callback callback, bool *woken)
{
// FIXME: only supports transfer sizes up to 255 bytes
struct pios_i2c_adapter *i2c_adapter = (struct pios_i2c_adapter *)i2c_id;
bool valid = PIOS_I2C_validate(i2c_adapter);
PIOS_Assert(valid)
PIOS_DEBUG_Assert(txn_list);
PIOS_DEBUG_Assert(num_txns);
#ifdef PIOS_INCLUDE_FREERTOS
signed portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
/* Lock the bus */
bool locked = xSemaphoreTakeFromISR(i2c_adapter->sem_busy, &xHigherPriorityTaskWoken) == pdTRUE;
if (xHigherPriorityTaskWoken == pdTRUE) {
*woken = true;
}
if (!locked) {
return -2;
}
#else
PIOS_IRQ_Disable();
if (i2c_adapter->busy) {
PIOS_IRQ_Enable();
return -2;
}
i2c_adapter->busy = 1;
PIOS_IRQ_Enable();
#endif /* PIOS_INCLUDE_FREERTOS */
return PIOS_I2C_Transfer_Callback_Internal(i2c_adapter, txn_list, num_txns, callback);
}
static bool i2c_adapter_callback_handler(struct pios_i2c_adapter *i2c_adapter, bool *woken)
{
#ifdef PIOS_INCLUDE_FREERTOS
/* Unlock the bus */
signed portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
xSemaphoreGiveFromISR(i2c_adapter->sem_busy, &xHigherPriorityTaskWoken);
if (xHigherPriorityTaskWoken == pdTRUE) {
*woken = true;
}
#else
PIOS_IRQ_Disable();
i2c_adapter->busy = 0;
PIOS_IRQ_Enable();
#endif /* PIOS_INCLUDE_FREERTOS */
// Execute user supplied function
if (i2c_adapter->callback()) {
*woken = true;
}
return !i2c_adapter->bus_error;
}
void PIOS_I2C_EV_IRQ_Handler(uint32_t i2c_id)
{
struct pios_i2c_adapter *i2c_adapter = (struct pios_i2c_adapter *)i2c_id;
bool valid = PIOS_I2C_validate(i2c_adapter);
PIOS_Assert(valid)
bool woken = false;
if (I2C_GetFlagStatus(i2c_adapter->cfg->regs, I2C_FLAG_RXNE)) {
// flag will be cleared by event
#if defined(PIOS_I2C_DIAGNOSTICS)
i2c_evirq_history[i2c_evirq_history_pointer] = I2C_FLAG_RXNE;
i2c_evirq_history_pointer = (i2c_evirq_history_pointer + 1) % I2C_LOG_DEPTH;
#endif
i2c_adapter_inject_event(i2c_adapter, I2C_EVENT_RECEIVER_BUFFER_NOT_EMPTY, &woken);
} else if (I2C_GetFlagStatus(i2c_adapter->cfg->regs, I2C_FLAG_TXIS)) {
// flag will be cleared by event
#if defined(PIOS_I2C_DIAGNOSTICS)
i2c_evirq_history[i2c_evirq_history_pointer] = I2C_FLAG_TXIS;
i2c_evirq_history_pointer = (i2c_evirq_history_pointer + 1) % I2C_LOG_DEPTH;
#endif
i2c_adapter_inject_event(i2c_adapter, I2C_EVENT_TRANSMIT_BUFFER_EMPTY, &woken);
} else if (I2C_GetFlagStatus(i2c_adapter->cfg->regs, I2C_FLAG_NACKF)) {
I2C_ClearFlag(i2c_adapter->cfg->regs, I2C_FLAG_NACKF);
#if defined(PIOS_I2C_DIAGNOSTICS)
i2c_evirq_history[i2c_evirq_history_pointer] = I2C_FLAG_NACKF;
i2c_evirq_history_pointer = (i2c_evirq_history_pointer + 1) % I2C_LOG_DEPTH;
++i2c_nack_counter;
#endif
i2c_adapter_inject_event(i2c_adapter, I2C_EVENT_NACK, &woken);
} else if (I2C_GetFlagStatus(i2c_adapter->cfg->regs, I2C_FLAG_TC)) {
I2C_ClearFlag(i2c_adapter->cfg->regs, I2C_FLAG_TC);
#if defined(PIOS_I2C_DIAGNOSTICS)
i2c_evirq_history[i2c_evirq_history_pointer] = I2C_FLAG_TC;
i2c_evirq_history_pointer = (i2c_evirq_history_pointer + 1) % I2C_LOG_DEPTH;
#endif
i2c_adapter_inject_event(i2c_adapter, I2C_EVENT_TRANSFER_COMPLETE, &woken);
} else if (I2C_GetFlagStatus(i2c_adapter->cfg->regs, I2C_FLAG_STOPF)) {
I2C_ClearFlag(i2c_adapter->cfg->regs, I2C_FLAG_STOPF);
#if defined(PIOS_I2C_DIAGNOSTICS)
i2c_evirq_history[i2c_evirq_history_pointer] = I2C_FLAG_STOPF;
i2c_evirq_history_pointer = (i2c_evirq_history_pointer + 1) % I2C_LOG_DEPTH;
#endif
i2c_adapter_inject_event(i2c_adapter, I2C_EVENT_STOP, &woken);
}
portEND_SWITCHING_ISR(woken ? pdTRUE : pdFALSE);
}
void PIOS_I2C_ER_IRQ_Handler(uint32_t i2c_id)
{
struct pios_i2c_adapter *i2c_adapter = (struct pios_i2c_adapter *)i2c_id;
bool valid = PIOS_I2C_validate(i2c_adapter);
PIOS_Assert(valid)
else if (I2C_GetFlagStatus(i2c_adapter->cfg->regs, I2C_FLAG_BERR)) {
I2C_ClearFlag(i2c_adapter->cfg->regs, I2C_FLAG_BERR);
#if defined(PIOS_I2C_DIAGNOSTICS)
i2c_erirq_history[i2c_erirq_history_pointer] = I2C_FLAG_BERR;
i2c_erirq_history_pointer = (i2c_erirq_history_pointer + 1) % I2C_LOG_DEPTH;
#endif
} else if (I2C_GetFlagStatus(i2c_adapter->cfg->regs, I2C_FLAG_ARLO)) {
I2C_ClearFlag(i2c_adapter->cfg->regs, I2C_FLAG_ARLO);
#if defined(PIOS_I2C_DIAGNOSTICS)
i2c_erirq_history[i2c_erirq_history_pointer] = I2C_FLAG_ARLO;
i2c_erirq_history_pointer = (i2c_erirq_history_pointer + 1) % I2C_LOG_DEPTH;
#endif
} else if (I2C_GetFlagStatus(i2c_adapter->cfg->regs, I2C_FLAG_OVR)) {
I2C_ClearFlag(i2c_adapter->cfg->regs, I2C_FLAG_OVR);
#if defined(PIOS_I2C_DIAGNOSTICS)
i2c_erirq_history[i2c_erirq_history_pointer] = I2C_FLAG_OVR;
i2c_erirq_history_pointer = (i2c_erirq_history_pointer + 1) % I2C_LOG_DEPTH;
#endif
} else if (I2C_GetFlagStatus(i2c_adapter->cfg->regs, I2C_FLAG_PECERR)) {
I2C_ClearFlag(i2c_adapter->cfg->regs, I2C_FLAG_PECERR);
#if defined(PIOS_I2C_DIAGNOSTICS)
i2c_erirq_history[i2c_erirq_history_pointer] = I2C_FLAG_PECERR;
i2c_erirq_history_pointer = (i2c_erirq_history_pointer + 1) % I2C_LOG_DEPTH;
#endif
} else if (I2C_GetFlagStatus(i2c_adapter->cfg->regs, I2C_FLAG_TIMEOUT)) {
I2C_ClearFlag(i2c_adapter->cfg->regs, I2C_FLAG_TIMEOUT);
#if defined(PIOS_I2C_DIAGNOSTICS)
i2c_erirq_history[i2c_erirq_history_pointer] = I2C_FLAG_TIMEOUT;
i2c_erirq_history_pointer = (i2c_erirq_history_pointer + 1) % I2C_LOG_DEPTH;
#endif
} else if (I2C_GetFlagStatus(i2c_adapter->cfg->regs, I2C_FLAG_ALERT)) {
I2C_ClearFlag(i2c_adapter->cfg->regs, I2C_FLAG_ALERT);
#if defined(PIOS_I2C_DIAGNOSTICS)
i2c_erirq_history[i2c_erirq_history_pointer] = I2C_FLAG_ALERT;
i2c_erirq_history_pointer = (i2c_erirq_history_pointer + 1) % I2C_LOG_DEPTH;
#endif
} else if (I2C_GetFlagStatus(i2c_adapter->cfg->regs, I2C_FLAG_BUSY)) {
I2C_ClearFlag(i2c_adapter->cfg->regs, I2C_FLAG_BUSY);
#if defined(PIOS_I2C_DIAGNOSTICS)
i2c_erirq_history[i2c_erirq_history_pointer] = I2C_FLAG_BUSY;
i2c_erirq_history_pointer = (i2c_erirq_history_pointer + 1) % I2C_LOG_DEPTH;
#endif
}
#if defined(PIOS_I2C_DIAGNOSTICS)
i2c_adapter_log_fault(i2c_adapter, PIOS_I2C_ERROR_INTERRUPT);
#endif
/* Fail hard on any errors for now */
bool woken = false;
i2c_adapter_inject_event(i2c_adapter, I2C_EVENT_BUS_ERROR, &woken);
portEND_SWITCHING_ISR(woken ? pdTRUE : pdFALSE);
}
#endif /* if defined(PIOS_INCLUDE_I2C) */
/**
* @}
* @}
*/

View File

@ -0,0 +1,97 @@
/**
******************************************************************************
* @addtogroup PIOS PIOS Core hardware abstraction layer
* @{
* @addtogroup PIOS_IRQ IRQ Setup Functions
* @brief STM32 Hardware code to enable and disable interrupts
* @{
*
* @file pios_irq.c
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* Parts by Thorsten Klose (tk@midibox.org) (tk@midibox.org)
* @brief IRQ Enable/Disable routines
* @see The GNU Public License (GPL) Version 3
*
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "pios.h"
#ifdef PIOS_INCLUDE_IRQ
/* Private Function Prototypes */
/* Local Variables */
/* The nesting counter ensures, that interrupts won't be enabled so long nested functions disable them */
static uint32_t nested_ctr;
/* Stored priority level before IRQ has been disabled (important for co-existence with vPortEnterCritical) */
static uint32_t prev_primask;
/**
* Disables all interrupts (nested)
* \return < 0 On errors
*/
int32_t PIOS_IRQ_Disable(void)
{
/* Get current priority if nested level == 0 */
if (!nested_ctr) {
__asm volatile (" mrs %0, primask\n" : "=r" (prev_primask)
);
}
/* Disable interrupts */
__asm volatile (" mov r0, #1 \n" " msr primask, r0\n" ::: "r0");
++nested_ctr;
/* No error */
return 0;
}
/**
* Enables all interrupts (nested)
* \return < 0 on errors
* \return -1 on nesting errors (PIOS_IRQ_Disable() hasn't been called before)
*/
int32_t PIOS_IRQ_Enable(void)
{
/* Check for nesting error */
if (nested_ctr == 0) {
/* Nesting error */
return -1;
}
/* Decrease nesting level */
--nested_ctr;
/* Set back previous priority once nested level reached 0 again */
if (nested_ctr == 0) {
__asm volatile (" msr primask, %0\n" ::"r" (prev_primask)
);
}
/* No error */
return 0;
}
#endif /* PIOS_INCLUDE_IRQ */
/**
* @}
* @}
*/

View File

@ -0,0 +1,401 @@
/**
******************************************************************************
* @addtogroup PIOS PIOS Core hardware abstraction layer
* @{
* @addtogroup PIOS_PPM PPM Input Functions
* @brief Code to measure PPM input and seperate into channels
* @{
*
* @file pios_ppm.c
* @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2016.
* The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
* @brief PPM Input functions (STM32 dependent)
* @see The GNU Public License (GPL) Version 3
*
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "pios.h"
#ifdef PIOS_INCLUDE_PPM
#include "pios_ppm_priv.h"
/* Provide a RCVR driver */
static int32_t PIOS_PPM_Get(uint32_t rcvr_id, uint8_t channel);
static xSemaphoreHandle PIOS_PPM_Get_Semaphore(uint32_t rcvr_id, uint8_t channel);
const struct pios_rcvr_driver pios_ppm_rcvr_driver = {
.read = PIOS_PPM_Get,
#if defined(PIOS_INCLUDE_FREERTOS)
.get_semaphore = PIOS_PPM_Get_Semaphore
#endif
};
#define PIOS_PPM_IN_MIN_NUM_CHANNELS 4
#define PIOS_PPM_IN_MAX_NUM_CHANNELS PIOS_PPM_NUM_INPUTS
#define PIOS_PPM_STABLE_CHANNEL_COUNT 25 // frames
#define PIOS_PPM_IN_MIN_SYNC_PULSE_US 2700 // microseconds
#define PIOS_PPM_IN_MIN_CHANNEL_PULSE_US 750 // microseconds
#define PIOS_PPM_IN_MAX_CHANNEL_PULSE_US 2250 // microseconds
static void PIOS_PPM_Supervisor(uint32_t ppm_id);
enum pios_ppm_dev_magic {
PIOS_PPM_DEV_MAGIC = 0xee014d8b,
};
struct pios_ppm_dev {
enum pios_ppm_dev_magic magic;
const struct pios_ppm_cfg *cfg;
uint8_t PulseIndex;
uint32_t PreviousTime;
uint32_t CurrentTime;
uint32_t DeltaTime;
uint32_t CaptureValue[PIOS_PPM_IN_MAX_NUM_CHANNELS];
uint32_t CaptureValueNewFrame[PIOS_PPM_IN_MAX_NUM_CHANNELS];
uint32_t LargeCounter;
int8_t NumChannels;
int8_t NumChannelsPrevFrame;
uint8_t NumChannelCounter;
uint8_t supv_timer;
bool Tracking;
bool Fresh;
#ifdef PIOS_INCLUDE_FREERTOS
xSemaphoreHandle new_sample_semaphores[PIOS_PPM_IN_MIN_NUM_CHANNELS];
#endif /* PIOS_INCLUDE_FREERTOS */
};
static bool PIOS_PPM_validate(struct pios_ppm_dev *ppm_dev)
{
return ppm_dev->magic == PIOS_PPM_DEV_MAGIC;
}
#if defined(PIOS_INCLUDE_FREERTOS)
static struct pios_ppm_dev *PIOS_PPM_alloc(void)
{
struct pios_ppm_dev *ppm_dev;
ppm_dev = (struct pios_ppm_dev *)pios_malloc(sizeof(*ppm_dev));
if (!ppm_dev) {
return NULL;
}
// Initialize the semaphores to 0.
for (uint8_t i = 0; i < PIOS_PPM_IN_MIN_NUM_CHANNELS; ++i) {
ppm_dev->new_sample_semaphores[i] = 0;
}
ppm_dev->magic = PIOS_PPM_DEV_MAGIC;
return ppm_dev;
}
#else
static struct pios_ppm_dev pios_ppm_devs[PIOS_PPM_MAX_DEVS];
static uint8_t pios_ppm_num_devs;
static struct pios_ppm_dev *PIOS_PPM_alloc(void)
{
struct pios_ppm_dev *ppm_dev;
if (pios_ppm_num_devs >= PIOS_PPM_MAX_DEVS) {
return NULL;
}
ppm_dev = &pios_ppm_devs[pios_ppm_num_devs++];
ppm_dev->magic = PIOS_PPM_DEV_MAGIC;
return ppm_dev;
}
#endif /* if defined(PIOS_INCLUDE_FREERTOS) */
static void PIOS_PPM_tim_overflow_cb(uint32_t id, uint32_t context, uint8_t channel, uint16_t count);
static void PIOS_PPM_tim_edge_cb(uint32_t id, uint32_t context, uint8_t channel, uint16_t count);
static const struct pios_tim_callbacks tim_callbacks = {
.overflow = PIOS_PPM_tim_overflow_cb,
.edge = PIOS_PPM_tim_edge_cb,
};
extern int32_t PIOS_PPM_Init(uint32_t *ppm_id, const struct pios_ppm_cfg *cfg)
{
PIOS_DEBUG_Assert(ppm_id);
PIOS_DEBUG_Assert(cfg);
struct pios_ppm_dev *ppm_dev;
ppm_dev = (struct pios_ppm_dev *)PIOS_PPM_alloc();
if (!ppm_dev) {
goto out_fail;
}
/* Bind the configuration to the device instance */
ppm_dev->cfg = cfg;
/* Set up the state variables */
ppm_dev->PulseIndex = 0;
ppm_dev->PreviousTime = 0;
ppm_dev->CurrentTime = 0;
ppm_dev->DeltaTime = 0;
ppm_dev->LargeCounter = 0;
ppm_dev->NumChannels = -1;
ppm_dev->NumChannelsPrevFrame = -1;
ppm_dev->NumChannelCounter = 0;
ppm_dev->Tracking = false;
ppm_dev->Fresh = false;
for (uint8_t i = 0; i < PIOS_PPM_IN_MAX_NUM_CHANNELS; i++) {
/* Flush counter variables */
ppm_dev->CaptureValue[i] = PIOS_RCVR_TIMEOUT;
ppm_dev->CaptureValueNewFrame[i] = PIOS_RCVR_TIMEOUT;
}
uint32_t tim_id;
if (PIOS_TIM_InitChannels(&tim_id, cfg->channels, cfg->num_channels, &tim_callbacks, (uint32_t)ppm_dev)) {
return -1;
}
TIM_ICInitTypeDef TIM_ICInitStructure = cfg->tim_ic_init;
/* Configure the channels to be in capture/compare mode */
for (uint8_t i = 0; i < cfg->num_channels; i++) {
const struct pios_tim_channel *chan = &cfg->channels[i];
/* Configure timer for input capture */
TIM_ICInitStructure.TIM_Channel = chan->timer_chan;
TIM_ICInit(chan->timer, &TIM_ICInitStructure);
/* Enable the Capture Compare Interrupt Request */
switch (chan->timer_chan) {
case TIM_Channel_1:
TIM_ITConfig(chan->timer, TIM_IT_CC1 | TIM_IT_Update, ENABLE);
break;
case TIM_Channel_2:
TIM_ITConfig(chan->timer, TIM_IT_CC2 | TIM_IT_Update, ENABLE);
break;
case TIM_Channel_3:
TIM_ITConfig(chan->timer, TIM_IT_CC3 | TIM_IT_Update, ENABLE);
break;
case TIM_Channel_4:
TIM_ITConfig(chan->timer, TIM_IT_CC4 | TIM_IT_Update, ENABLE);
break;
}
}
if (!PIOS_RTC_RegisterTickCallback(PIOS_PPM_Supervisor, (uint32_t)ppm_dev)) {
PIOS_DEBUG_Assert(0);
}
*ppm_id = (uint32_t)ppm_dev;
return 0;
out_fail:
return -1;
}
#if defined(PIOS_INCLUDE_FREERTOS)
static xSemaphoreHandle PIOS_PPM_Get_Semaphore(uint32_t rcvr_id, uint8_t channel)
{
struct pios_ppm_dev *ppm_dev = (struct pios_ppm_dev *)rcvr_id;
if (!PIOS_PPM_validate(ppm_dev)) {
/* Invalid device specified */
return 0;
}
if (channel >= PIOS_PPM_IN_MAX_NUM_CHANNELS) {
/* Channel out of range */
return 0;
}
if (ppm_dev->new_sample_semaphores[channel] == 0) {
vSemaphoreCreateBinary(ppm_dev->new_sample_semaphores[channel]);
}
return ppm_dev->new_sample_semaphores[channel];
}
#endif /* if defined(PIOS_INCLUDE_FREERTOS) */
/**
* Get the value of an input channel
* \param[in] channel Number of the channel desired (zero based)
* \output PIOS_RCVR_INVALID channel not available
* \output PIOS_RCVR_TIMEOUT failsafe condition or missing receiver
* \output >=0 channel value
*/
static int32_t PIOS_PPM_Get(uint32_t rcvr_id, uint8_t channel)
{
struct pios_ppm_dev *ppm_dev = (struct pios_ppm_dev *)rcvr_id;
if (!PIOS_PPM_validate(ppm_dev)) {
/* Invalid device specified */
return PIOS_RCVR_INVALID;
}
if (channel >= PIOS_PPM_IN_MAX_NUM_CHANNELS) {
/* Channel out of range */
return PIOS_RCVR_INVALID;
}
return ppm_dev->CaptureValue[channel];
}
static void PIOS_PPM_tim_overflow_cb(__attribute__((unused)) uint32_t tim_id, uint32_t context,
__attribute__((unused)) uint8_t channel, uint16_t count)
{
struct pios_ppm_dev *ppm_dev = (struct pios_ppm_dev *)context;
if (!PIOS_PPM_validate(ppm_dev)) {
/* Invalid device specified */
return;
}
ppm_dev->LargeCounter += count;
}
static void PIOS_PPM_tim_edge_cb(__attribute__((unused)) uint32_t tim_id, uint32_t context, uint8_t chan_idx, uint16_t count)
{
/* Recover our device context */
struct pios_ppm_dev *ppm_dev = (struct pios_ppm_dev *)context;
if (!PIOS_PPM_validate(ppm_dev)) {
/* Invalid device specified */
return;
}
if (chan_idx >= ppm_dev->cfg->num_channels) {
/* Channel out of range */
return;
}
/* Shift the last measurement out */
ppm_dev->PreviousTime = ppm_dev->CurrentTime;
/* Grab the new count */
ppm_dev->CurrentTime = count;
/* Convert to 32-bit timer result */
ppm_dev->CurrentTime += ppm_dev->LargeCounter;
/* Capture computation */
ppm_dev->DeltaTime = ppm_dev->CurrentTime - ppm_dev->PreviousTime;
ppm_dev->PreviousTime = ppm_dev->CurrentTime;
/* Sync pulse detection */
if (ppm_dev->DeltaTime > PIOS_PPM_IN_MIN_SYNC_PULSE_US) {
if (ppm_dev->PulseIndex == ppm_dev->NumChannelsPrevFrame
&& ppm_dev->PulseIndex >= PIOS_PPM_IN_MIN_NUM_CHANNELS
&& ppm_dev->PulseIndex <= PIOS_PPM_IN_MAX_NUM_CHANNELS) {
/* If we see n simultaneous frames of the same
number of channels we save it as our frame size */
if (ppm_dev->NumChannelCounter < PIOS_PPM_STABLE_CHANNEL_COUNT) {
ppm_dev->NumChannelCounter++;
} else {
ppm_dev->NumChannels = ppm_dev->PulseIndex;
}
} else {
ppm_dev->NumChannelCounter = 0;
}
/* Check if the last frame was well formed */
if (ppm_dev->PulseIndex == ppm_dev->NumChannels && ppm_dev->Tracking) {
/* The last frame was well formed */
for (int32_t i = 0; i < ppm_dev->NumChannels; i++) {
ppm_dev->CaptureValue[i] = ppm_dev->CaptureValueNewFrame[i];
}
for (uint32_t i = ppm_dev->NumChannels;
i < PIOS_PPM_IN_MAX_NUM_CHANNELS; i++) {
ppm_dev->CaptureValue[i] = PIOS_RCVR_TIMEOUT;
}
#if defined(PIOS_INCLUDE_FREERTOS)
/* Signal that a new sample is ready on this channel. */
if (ppm_dev->new_sample_semaphores[chan_idx] != 0) {
signed portBASE_TYPE pxHigherPriorityTaskWoken = pdFALSE;
if (xSemaphoreGiveFromISR(ppm_dev->new_sample_semaphores[chan_idx], &pxHigherPriorityTaskWoken) == pdTRUE) {
portEND_SWITCHING_ISR(pxHigherPriorityTaskWoken); /* FIXME: is this the right place for his? */
}
}
#endif /* USE_FREERTOS */
} else {
for (uint32_t i = 0;
i < PIOS_PPM_IN_MAX_NUM_CHANNELS; i++) {
ppm_dev->CaptureValue[i] = PIOS_RCVR_TIMEOUT;
}
}
ppm_dev->Fresh = true;
ppm_dev->Tracking = true;
ppm_dev->NumChannelsPrevFrame = ppm_dev->PulseIndex;
ppm_dev->PulseIndex = 0;
/* We rely on the supervisor to set CaptureValue to invalid
if no valid frame is found otherwise we ride over it */
} else if (ppm_dev->Tracking) {
/* Valid pulse duration 0.75 to 2.5 ms*/
if (ppm_dev->DeltaTime > PIOS_PPM_IN_MIN_CHANNEL_PULSE_US
&& ppm_dev->DeltaTime < PIOS_PPM_IN_MAX_CHANNEL_PULSE_US
&& ppm_dev->PulseIndex < PIOS_PPM_IN_MAX_NUM_CHANNELS) {
ppm_dev->CaptureValueNewFrame[ppm_dev->PulseIndex] = ppm_dev->DeltaTime;
ppm_dev->PulseIndex++;
} else {
/* Not a valid pulse duration */
ppm_dev->Tracking = false;
for (uint32_t i = 0; i < PIOS_PPM_IN_MAX_NUM_CHANNELS; i++) {
ppm_dev->CaptureValueNewFrame[i] = PIOS_RCVR_TIMEOUT;
}
}
}
}
static void PIOS_PPM_Supervisor(uint32_t ppm_id)
{
/* Recover our device context */
struct pios_ppm_dev *ppm_dev = (struct pios_ppm_dev *)ppm_id;
if (!PIOS_PPM_validate(ppm_dev)) {
/* Invalid device specified */
return;
}
/*
* RTC runs at 625Hz so divide down the base rate so
* that this loop runs at 25Hz.
*/
if (++(ppm_dev->supv_timer) < 25) {
return;
}
ppm_dev->supv_timer = 0;
if (!ppm_dev->Fresh) {
ppm_dev->Tracking = false;
for (int32_t i = 0; i < PIOS_PPM_IN_MAX_NUM_CHANNELS; i++) {
ppm_dev->CaptureValue[i] = PIOS_RCVR_TIMEOUT;
ppm_dev->CaptureValueNewFrame[i] = PIOS_RCVR_TIMEOUT;
}
}
ppm_dev->Fresh = false;
}
#endif /* PIOS_INCLUDE_PPM */
/**
* @}
* @}
*/

View File

@ -0,0 +1,283 @@
/**
******************************************************************************
* @addtogroup PIOS PIOS Core hardware abstraction layer
* @{
* @addtogroup PIOS_PWM PWM Input Functions
* @brief Code to measure with PWM input
* @{
*
* @file pios_pwm.c
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
* @brief PWM Input functions (STM32 dependent)
* @see The GNU Public License (GPL) Version 3
*
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "pios.h"
#ifdef PIOS_INCLUDE_PWM
#include "pios_pwm_priv.h"
/* Provide a RCVR driver */
static int32_t PIOS_PWM_Get(uint32_t rcvr_id, uint8_t channel);
const struct pios_rcvr_driver pios_pwm_rcvr_driver = {
.read = PIOS_PWM_Get,
};
/* Local Variables */
/* 100 ms timeout without updates on channels */
static const uint32_t PWM_SUPERVISOR_TIMEOUT = 100000;
enum pios_pwm_dev_magic {
PIOS_PWM_DEV_MAGIC = 0xab30293c,
};
struct pios_pwm_dev {
enum pios_pwm_dev_magic magic;
const struct pios_pwm_cfg *cfg;
uint8_t CaptureState[PIOS_PWM_NUM_INPUTS];
uint16_t RiseValue[PIOS_PWM_NUM_INPUTS];
uint16_t FallValue[PIOS_PWM_NUM_INPUTS];
uint32_t CaptureValue[PIOS_PWM_NUM_INPUTS];
uint32_t CapCounter[PIOS_PWM_NUM_INPUTS];
uint32_t us_since_update[PIOS_PWM_NUM_INPUTS];
};
static bool PIOS_PWM_validate(struct pios_pwm_dev *pwm_dev)
{
return pwm_dev->magic == PIOS_PWM_DEV_MAGIC;
}
#if defined(PIOS_INCLUDE_FREERTOS)
static struct pios_pwm_dev *PIOS_PWM_alloc(void)
{
struct pios_pwm_dev *pwm_dev;
pwm_dev = (struct pios_pwm_dev *)pios_malloc(sizeof(*pwm_dev));
if (!pwm_dev) {
return NULL;
}
pwm_dev->magic = PIOS_PWM_DEV_MAGIC;
return pwm_dev;
}
#else
static struct pios_pwm_dev pios_pwm_devs[PIOS_PWM_MAX_DEVS];
static uint8_t pios_pwm_num_devs;
static struct pios_pwm_dev *PIOS_PWM_alloc(void)
{
struct pios_pwm_dev *pwm_dev;
if (pios_pwm_num_devs >= PIOS_PWM_MAX_DEVS) {
return NULL;
}
pwm_dev = &pios_pwm_devs[pios_pwm_num_devs++];
pwm_dev->magic = PIOS_PWM_DEV_MAGIC;
return pwm_dev;
}
#endif /* if defined(PIOS_INCLUDE_FREERTOS) */
static void PIOS_PWM_tim_overflow_cb(uint32_t id, uint32_t context, uint8_t channel, uint16_t count);
static void PIOS_PWM_tim_edge_cb(uint32_t id, uint32_t context, uint8_t channel, uint16_t count);
static const struct pios_tim_callbacks tim_callbacks = {
.overflow = PIOS_PWM_tim_overflow_cb,
.edge = PIOS_PWM_tim_edge_cb,
};
/**
* Initialises all the pins
*/
int32_t PIOS_PWM_Init(uint32_t *pwm_id, const struct pios_pwm_cfg *cfg)
{
PIOS_DEBUG_Assert(pwm_id);
PIOS_DEBUG_Assert(cfg);
struct pios_pwm_dev *pwm_dev;
pwm_dev = (struct pios_pwm_dev *)PIOS_PWM_alloc();
if (!pwm_dev) {
goto out_fail;
}
/* Bind the configuration to the device instance */
pwm_dev->cfg = cfg;
for (uint8_t i = 0; i < PIOS_PWM_NUM_INPUTS; i++) {
/* Flush counter variables */
pwm_dev->CaptureState[i] = 0;
pwm_dev->RiseValue[i] = 0;
pwm_dev->FallValue[i] = 0;
pwm_dev->CaptureValue[i] = PIOS_RCVR_TIMEOUT;
}
uint32_t tim_id;
if (PIOS_TIM_InitChannels(&tim_id, cfg->channels, cfg->num_channels, &tim_callbacks, (uint32_t)pwm_dev)) {
return -1;
}
/* Configure the channels to be in capture/compare mode */
for (uint8_t i = 0; i < cfg->num_channels; i++) {
const struct pios_tim_channel *chan = &cfg->channels[i];
/* Configure timer for input capture */
TIM_ICInitTypeDef TIM_ICInitStructure = cfg->tim_ic_init;
TIM_ICInitStructure.TIM_Channel = chan->timer_chan;
TIM_ICInit(chan->timer, &TIM_ICInitStructure);
/* Enable the Capture Compare Interrupt Request */
switch (chan->timer_chan) {
case TIM_Channel_1:
TIM_ITConfig(chan->timer, TIM_IT_CC1, ENABLE);
break;
case TIM_Channel_2:
TIM_ITConfig(chan->timer, TIM_IT_CC2, ENABLE);
break;
case TIM_Channel_3:
TIM_ITConfig(chan->timer, TIM_IT_CC3, ENABLE);
break;
case TIM_Channel_4:
TIM_ITConfig(chan->timer, TIM_IT_CC4, ENABLE);
break;
}
// Need the update event for that timer to detect timeouts
TIM_ITConfig(chan->timer, TIM_IT_Update, ENABLE);
}
*pwm_id = (uint32_t)pwm_dev;
return 0;
out_fail:
return -1;
}
/**
* Get the value of an input channel
* \param[in] channel Number of the channel desired (zero based)
* \output PIOS_RCVR_INVALID channel not available
* \output PIOS_RCVR_TIMEOUT failsafe condition or missing receiver
* \output >=0 channel value
*/
static int32_t PIOS_PWM_Get(uint32_t rcvr_id, uint8_t channel)
{
struct pios_pwm_dev *pwm_dev = (struct pios_pwm_dev *)rcvr_id;
if (!PIOS_PWM_validate(pwm_dev)) {
/* Invalid device specified */
return PIOS_RCVR_INVALID;
}
if (channel >= PIOS_PWM_NUM_INPUTS) {
/* Channel out of range */
return PIOS_RCVR_INVALID;
}
return pwm_dev->CaptureValue[channel];
}
static void PIOS_PWM_tim_overflow_cb(__attribute__((unused)) uint32_t tim_id, uint32_t context, uint8_t channel, uint16_t count)
{
struct pios_pwm_dev *pwm_dev = (struct pios_pwm_dev *)context;
if (!PIOS_PWM_validate(pwm_dev)) {
/* Invalid device specified */
return;
}
if (channel >= pwm_dev->cfg->num_channels) {
/* Channel out of range */
return;
}
pwm_dev->us_since_update[channel] += count;
if (pwm_dev->us_since_update[channel] >= PWM_SUPERVISOR_TIMEOUT) {
pwm_dev->CaptureState[channel] = 0;
pwm_dev->RiseValue[channel] = 0;
pwm_dev->FallValue[channel] = 0;
pwm_dev->CaptureValue[channel] = PIOS_RCVR_TIMEOUT;
pwm_dev->us_since_update[channel] = 0;
}
}
static void PIOS_PWM_tim_edge_cb(__attribute__((unused)) uint32_t tim_id, uint32_t context, uint8_t chan_idx, uint16_t count)
{
/* Recover our device context */
struct pios_pwm_dev *pwm_dev = (struct pios_pwm_dev *)context;
if (!PIOS_PWM_validate(pwm_dev)) {
/* Invalid device specified */
return;
}
if (chan_idx >= pwm_dev->cfg->num_channels) {
/* Channel out of range */
return;
}
const struct pios_tim_channel *chan = &pwm_dev->cfg->channels[chan_idx];
if (pwm_dev->CaptureState[chan_idx] == 0) {
pwm_dev->RiseValue[chan_idx] = count;
pwm_dev->us_since_update[chan_idx] = 0;
} else {
pwm_dev->FallValue[chan_idx] = count;
}
// flip state machine and capture value here
/* Simple rise or fall state machine */
TIM_ICInitTypeDef TIM_ICInitStructure = pwm_dev->cfg->tim_ic_init;
if (pwm_dev->CaptureState[chan_idx] == 0) {
/* Switch states */
pwm_dev->CaptureState[chan_idx] = 1;
/* Switch polarity of input capture */
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Falling;
TIM_ICInitStructure.TIM_Channel = chan->timer_chan;
TIM_ICInit(chan->timer, &TIM_ICInitStructure);
} else {
/* Capture computation */
if (pwm_dev->FallValue[chan_idx] > pwm_dev->RiseValue[chan_idx]) {
pwm_dev->CaptureValue[chan_idx] = (pwm_dev->FallValue[chan_idx] - pwm_dev->RiseValue[chan_idx]);
} else {
pwm_dev->CaptureValue[chan_idx] = ((chan->timer->ARR - pwm_dev->RiseValue[chan_idx]) + pwm_dev->FallValue[chan_idx]);
}
/* Switch states */
pwm_dev->CaptureState[chan_idx] = 0;
/* Increase supervisor counter */
pwm_dev->CapCounter[chan_idx]++;
/* Switch polarity of input capture */
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
TIM_ICInitStructure.TIM_Channel = chan->timer_chan;
TIM_ICInit(chan->timer, &TIM_ICInitStructure);
}
}
#endif /* PIOS_INCLUDE_PWM */
/**
* @}
* @}
*/

View File

@ -0,0 +1,141 @@
/**
******************************************************************************
* @addtogroup PIOS PIOS Core hardware abstraction layer
* @{
* @addtogroup PIOS_RTC RTC Functions
* @brief Code to manage initialization and interrups of RTC peripheral
* @{
*
* @file pios_rtc.c
* @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017.
* The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
* @brief RTC Functions (STM32 dependent)
* @see The GNU Public License (GPL) Version 3
*
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "pios.h"
#ifdef PIOS_INCLUDE_RTC
#include <pios_rtc_priv.h>
#ifndef PIOS_RTC_PRESCALER
#define PIOS_RTC_PRESCALER 100
#endif
struct rtc_callback_entry {
void (*fn)(uint32_t);
uint32_t data;
};
#define PIOS_RTC_MAX_CALLBACKS 3
struct rtc_callback_entry rtc_callback_list[PIOS_RTC_MAX_CALLBACKS];
static uint8_t rtc_callback_next = 0;
void PIOS_RTC_Init(const struct pios_rtc_cfg *cfg)
{
RCC_BackupResetCmd(ENABLE);
RCC_BackupResetCmd(DISABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
PWR_BackupAccessCmd(ENABLE);
// Divide external 8 MHz clock to 1 MHz
RCC_RTCCLKConfig(cfg->clksrc);
RCC_RTCCLKCmd(ENABLE);
RTC_WakeUpCmd(DISABLE);
// Divide 1 Mhz clock by 16 -> 62.5 khz
RTC_WakeUpClockConfig(RTC_WakeUpClock_RTCCLK_Div16);
// Divide 62.5 khz by 200 to get 625 Hz
RTC_SetWakeUpCounter(cfg->prescaler); // cfg->prescaler);
RTC_WakeUpCmd(ENABLE);
/* Configure and enable the RTC Second interrupt */
EXTI_InitTypeDef ExtiInit = {
.EXTI_Line = EXTI_Line20, // matches above GPIO pin
.EXTI_Mode = EXTI_Mode_Interrupt,
.EXTI_Trigger = EXTI_Trigger_Rising,
.EXTI_LineCmd = ENABLE,
};
EXTI_Init((EXTI_InitTypeDef *)&ExtiInit);
NVIC_Init((NVIC_InitTypeDef *)&cfg->irq.init);
RTC_ITConfig(RTC_IT_WUT, ENABLE);
RTC_ClearFlag(RTC_FLAG_WUTF);
}
uint32_t PIOS_RTC_Counter()
{
return RTC_GetWakeUpCounter();
}
/* FIXME: This shouldn't use hard-coded clock rates, dividers or prescalers.
* Should get these from the cfg struct passed to init.
*/
float PIOS_RTC_Rate()
{
return (float)(8e6f / 128.0f) / (1 + PIOS_RTC_PRESCALER);
}
float PIOS_RTC_MsPerTick()
{
return 1000.0f / PIOS_RTC_Rate();
}
/* TODO: This needs a mutex around rtc_callbacks[] */
bool PIOS_RTC_RegisterTickCallback(void (*fn)(uint32_t id), uint32_t data)
{
struct rtc_callback_entry *cb;
if (rtc_callback_next >= PIOS_RTC_MAX_CALLBACKS) {
return false;
}
cb = &rtc_callback_list[rtc_callback_next++];
cb->fn = fn;
cb->data = data;
return true;
}
void PIOS_RTC_irq_handler(void)
{
if (RTC_GetITStatus(RTC_IT_WUT)) {
/* Call all registered callbacks */
for (uint8_t i = 0; i < rtc_callback_next; i++) {
struct rtc_callback_entry *cb = &rtc_callback_list[i];
if (cb->fn) {
(cb->fn)(cb->data);
}
}
/* Clear the RTC Second interrupt */
RTC_ClearITPendingBit(RTC_IT_WUT);
}
if (EXTI_GetITStatus(EXTI_Line20) != RESET) {
EXTI_ClearITPendingBit(EXTI_Line20);
}
}
#endif /* PIOS_INCLUDE_RTC */
/**
* @}
* @}
*/

View File

@ -0,0 +1,751 @@
/**
******************************************************************************
* @addtogroup PIOS PIOS Core hardware abstraction layer
* @{
* @addtogroup PIOS_SPI SPI Functions
* @brief PIOS interface to read and write from SPI ports
* @{
*
* @file pios_spi.c
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
* @brief Hardware Abstraction Layer for SPI ports of STM32
* @see The GNU Public License (GPL) Version 3
* @notes
*
* Note that additional chip select lines can be easily added by using
* the remaining free GPIOs of the core module. Shared SPI ports should be
* arbitrated with (FreeRTOS based) Mutexes to avoid collisions!
*
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <pios.h>
#ifdef PIOS_INCLUDE_SPI
#include <pios_spi_priv.h>
#define SPI_MAX_BLOCK_PIO 12800
static bool PIOS_SPI_validate(__attribute__((unused)) struct pios_spi_dev *com_dev)
{
/* Should check device magic here */
return true;
}
#if defined(PIOS_INCLUDE_FREERTOS)
static struct pios_spi_dev *PIOS_SPI_alloc(void)
{
return pios_malloc(sizeof(struct pios_spi_dev));
}
#else
static struct pios_spi_dev pios_spi_devs[PIOS_SPI_MAX_DEVS];
static uint8_t pios_spi_num_devs;
static struct pios_spi_dev *PIOS_SPI_alloc(void)
{
if (pios_spi_num_devs >= PIOS_SPI_MAX_DEVS) {
return NULL;
}
return &pios_spi_devs[pios_spi_num_devs++];
}
#endif
/**
* Initialises SPI pins
* \param[in] mode currently only mode 0 supported
* \return < 0 if initialisation failed
*/
int32_t PIOS_SPI_Init(uint32_t *spi_id, const struct pios_spi_cfg *cfg)
{
uint32_t init_ssel = 0;
PIOS_Assert(spi_id);
PIOS_Assert(cfg);
struct pios_spi_dev *spi_dev;
spi_dev = (struct pios_spi_dev *)PIOS_SPI_alloc();
if (!spi_dev) {
goto out_fail;
}
/* Bind the configuration to the device instance */
spi_dev->cfg = cfg;
#if defined(PIOS_INCLUDE_FREERTOS)
vSemaphoreCreateBinary(spi_dev->busy);
xSemaphoreGive(spi_dev->busy);
#else
spi_dev->busy = 0;
#endif
/* Disable callback function */
spi_dev->callback = NULL;
/* Set rx/tx dummy bytes to a known value */
spi_dev->rx_dummy_byte = 0xFF;
spi_dev->tx_dummy_byte = 0xFF;
switch (spi_dev->cfg->init.SPI_NSS) {
case SPI_NSS_Soft:
if (spi_dev->cfg->init.SPI_Mode == SPI_Mode_Master) {
/* We're a master in soft NSS mode, make sure we see NSS high at all times. */
SPI_NSSInternalSoftwareConfig(spi_dev->cfg->regs, SPI_NSSInternalSoft_Set);
/* Init as many slave selects as the config advertises. */
init_ssel = spi_dev->cfg->slave_count;
} else {
/* We're a slave in soft NSS mode, make sure we see NSS low at all times. */
SPI_NSSInternalSoftwareConfig(spi_dev->cfg->regs, SPI_NSSInternalSoft_Reset);
}
break;
case SPI_NSS_Hard:
/* only legal for single-slave config */
PIOS_Assert(spi_dev->cfg->slave_count == 1);
init_ssel = 1;
/* FIXME: Should this also call SPI_SSOutputCmd()? */
break;
default:
PIOS_Assert(0);
}
/* Initialize the GPIO pins */
/* note __builtin_ctz() due to the difference between GPIO_PinX and GPIO_PinSourceX */
if (spi_dev->cfg->remap) {
GPIO_PinAFConfig(spi_dev->cfg->sclk.gpio,
__builtin_ctz(spi_dev->cfg->sclk.init.GPIO_Pin),
spi_dev->cfg->remap);
GPIO_PinAFConfig(spi_dev->cfg->mosi.gpio,
__builtin_ctz(spi_dev->cfg->mosi.init.GPIO_Pin),
spi_dev->cfg->remap);
GPIO_PinAFConfig(spi_dev->cfg->miso.gpio,
__builtin_ctz(spi_dev->cfg->miso.init.GPIO_Pin),
spi_dev->cfg->remap);
for (uint32_t i = 0; i < init_ssel; i++) {
GPIO_PinAFConfig(spi_dev->cfg->ssel[i].gpio,
__builtin_ctz(spi_dev->cfg->ssel[i].init.GPIO_Pin),
spi_dev->cfg->remap);
}
}
/* Initialize the GPIO pins */
GPIO_Init(spi_dev->cfg->sclk.gpio, (GPIO_InitTypeDef *)&(spi_dev->cfg->sclk.init));
GPIO_Init(spi_dev->cfg->mosi.gpio, (GPIO_InitTypeDef *)&(spi_dev->cfg->mosi.init));
GPIO_Init(spi_dev->cfg->miso.gpio, (GPIO_InitTypeDef *)&(spi_dev->cfg->miso.init));
for (uint32_t i = 0; i < init_ssel; i++) {
/* Since we're driving the SSEL pin in software, ensure that the slave is deselected */
/* XXX multi-slave support - maybe have another SPI_NSS_ mode? */
GPIO_SetBits(spi_dev->cfg->ssel[i].gpio, spi_dev->cfg->ssel[i].init.GPIO_Pin);
GPIO_Init(spi_dev->cfg->ssel[i].gpio, (GPIO_InitTypeDef *)&(spi_dev->cfg->ssel[i].init));
}
/* Enable the associated peripheral clock */
switch ((uint32_t)spi_dev->cfg->regs) {
case (uint32_t)SPI1:
/* Enable SPI peripheral clock (APB2 == high speed) */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
break;
case (uint32_t)SPI2:
/* Enable SPI peripheral clock (APB1 == slow speed) */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
break;
case (uint32_t)SPI3:
/* Enable SPI peripheral clock (APB1 == slow speed) */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI3, ENABLE);
break;
}
bool use_dma = spi_dev->cfg->dma.rx.channel && spi_dev->cfg->dma.tx.channel;
/* Enable DMA clock */
if (use_dma) {
RCC_AHBPeriphClockCmd(spi_dev->cfg->dma.ahb_clk, ENABLE);
/* Configure DMA for SPI Rx */
DMA_Cmd(spi_dev->cfg->dma.rx.channel, DISABLE);
DMA_Init(spi_dev->cfg->dma.rx.channel, (DMA_InitTypeDef *)&(spi_dev->cfg->dma.rx.init));
/* Configure DMA for SPI Tx */
DMA_Cmd(spi_dev->cfg->dma.tx.channel, DISABLE);
DMA_Init(spi_dev->cfg->dma.tx.channel, (DMA_InitTypeDef *)&(spi_dev->cfg->dma.tx.init));
}
/* Initialize the SPI block */
SPI_I2S_DeInit(spi_dev->cfg->regs);
SPI_Init(spi_dev->cfg->regs, (SPI_InitTypeDef *)&(spi_dev->cfg->init));
/* Configure CRC calculation */
if (spi_dev->cfg->use_crc) {
SPI_CalculateCRC(spi_dev->cfg->regs, ENABLE);
} else {
SPI_CalculateCRC(spi_dev->cfg->regs, DISABLE);
}
/* Configure the RX FIFO Threshold -- 8 bits */
SPI_RxFIFOThresholdConfig(spi_dev->cfg->regs, SPI_RxFIFOThreshold_QF);
/* Enable SPI */
SPI_Cmd(spi_dev->cfg->regs, ENABLE);
/* Enable SPI interrupts to DMA */
if (use_dma) {
SPI_I2S_DMACmd(spi_dev->cfg->regs, SPI_I2S_DMAReq_Tx | SPI_I2S_DMAReq_Rx, ENABLE);
}
/* Configure DMA interrupt */
NVIC_Init((NVIC_InitTypeDef *)&(spi_dev->cfg->dma.irq.init));
*spi_id = (uint32_t)spi_dev;
return 0;
out_fail:
return -1;
}
/**
* (Re-)initialises SPI peripheral clock rate
*
* \param[in] spi SPI number (0 or 1)
* \param[in] spi_prescaler configures the SPI speed:
* <UL>
* <LI>PIOS_SPI_PRESCALER_2: sets clock rate 27.7~ nS @ 72 MHz (36 MBit/s) (only supported for spi==0, spi1 uses 4 instead)
* <LI>PIOS_SPI_PRESCALER_4: sets clock rate 55.5~ nS @ 72 MHz (18 MBit/s)
* <LI>PIOS_SPI_PRESCALER_8: sets clock rate 111.1~ nS @ 72 MHz (9 MBit/s)
* <LI>PIOS_SPI_PRESCALER_16: sets clock rate 222.2~ nS @ 72 MHz (4.5 MBit/s)
* <LI>PIOS_SPI_PRESCALER_32: sets clock rate 444.4~ nS @ 72 MHz (2.25 MBit/s)
* <LI>PIOS_SPI_PRESCALER_64: sets clock rate 888.8~ nS @ 72 MHz (1.125 MBit/s)
* <LI>PIOS_SPI_PRESCALER_128: sets clock rate 1.7~ nS @ 72 MHz (0.562 MBit/s)
* <LI>PIOS_SPI_PRESCALER_256: sets clock rate 3.5~ nS @ 72 MHz (0.281 MBit/s)
* </UL>
* \return 0 if no error
* \return -1 if disabled SPI port selected
* \return -3 if invalid spi_prescaler selected
*/
int32_t PIOS_SPI_SetClockSpeed(uint32_t spi_id, SPIPrescalerTypeDef spi_prescaler)
{
struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id;
bool valid = PIOS_SPI_validate(spi_dev);
PIOS_Assert(valid)
SPI_InitTypeDef SPI_InitStructure;
if (spi_prescaler >= 8) {
/* Invalid prescaler selected */
return -3;
}
/* Start with a copy of the default configuration for the peripheral */
SPI_InitStructure = spi_dev->cfg->init;
/* Adjust the prescaler for the peripheral's clock */
SPI_InitStructure.SPI_BaudRatePrescaler = ((uint16_t)spi_prescaler & 7) << 3;
/* Write back the new configuration */
SPI_Init(spi_dev->cfg->regs, &SPI_InitStructure);
PIOS_SPI_TransferByte(spi_id, 0xFF);
return 0;
}
/**
* Claim the SPI bus semaphore. Calling the SPI functions does not require this
* \param[in] spi SPI number (0 or 1)
* \return 0 if no error
* \return -1 if timeout before claiming semaphore
*/
int32_t PIOS_SPI_ClaimBus(uint32_t spi_id)
{
#if defined(PIOS_INCLUDE_FREERTOS)
struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id;
bool valid = PIOS_SPI_validate(spi_dev);
PIOS_Assert(valid)
if (xSemaphoreTake(spi_dev->busy, 0xffff) != pdTRUE) {
return -1;
}
#else
struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id;
uint32_t timeout = 0xffff;
while ((PIOS_SPI_Busy(spi_id) || spi_dev->busy) && --timeout) {
;
}
if (timeout == 0) { // timed out
return -1;
}
PIOS_IRQ_Disable();
if (spi_dev->busy) {
return -1;
}
spi_dev->busy = 1;
PIOS_IRQ_Enable();
#endif /* if defined(PIOS_INCLUDE_FREERTOS) */
return 0;
}
/**
* Claim the SPI bus semaphore from an ISR. Has no timeout.
* \param[in] spi SPI number (0 or 1)
* \param woken[in,out] If non-NULL, will be set to true if woken was false and a higher priority
* task has is now eligible to run, else unchanged
* \return 0 if no error
* \return -1 if timeout before claiming semaphore
*/
int32_t PIOS_SPI_ClaimBusISR(uint32_t spi_id, bool *woken)
{
#if defined(PIOS_INCLUDE_FREERTOS)
struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id;
signed portBASE_TYPE higherPriorityTaskWoken = pdFALSE;
bool valid = PIOS_SPI_validate(spi_dev);
PIOS_Assert(valid)
if (xSemaphoreTakeFromISR(spi_dev->busy, &higherPriorityTaskWoken) != pdTRUE) {
return -1;
}
if (woken) {
*woken = *woken || (higherPriorityTaskWoken == pdTRUE);
}
return 0;
#else
if (woken) {
*woken = false;
}
return PIOS_SPI_ClaimBus(spi_id);
#endif
}
/**
* Release the SPI bus semaphore. Calling the SPI functions does not require this
* \param[in] spi SPI number (0 or 1)
* \return 0 if no error
*/
int32_t PIOS_SPI_ReleaseBus(uint32_t spi_id)
{
#if defined(PIOS_INCLUDE_FREERTOS)
struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id;
bool valid = PIOS_SPI_validate(spi_dev);
PIOS_Assert(valid)
xSemaphoreGive(spi_dev->busy);
#else
struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id;
PIOS_IRQ_Disable();
spi_dev->busy = 0;
PIOS_IRQ_Enable();
#endif
return 0;
}
/**
* Release the SPI bus semaphore from ISR. Calling the SPI functions does not require this
* \param[in] spi SPI number (0 or 1)
* \param woken[in,out] If non-NULL, will be set to true if woken was false and a higher priority
* task has is now eligible to run, else unchanged
* \return 0 if no error
*/
int32_t PIOS_SPI_ReleaseBusISR(uint32_t spi_id, bool *woken)
{
#if defined(PIOS_INCLUDE_FREERTOS)
struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id;
signed portBASE_TYPE higherPriorityTaskWoken = pdFALSE;
bool valid = PIOS_SPI_validate(spi_dev);
PIOS_Assert(valid)
xSemaphoreGiveFromISR(spi_dev->busy, &higherPriorityTaskWoken);
if (woken) {
*woken = *woken || (higherPriorityTaskWoken == pdTRUE);
}
return 0;
#else
if (woken) {
*woken = false;
}
return PIOS_SPI_ReleaseBus(spi_id);
#endif
}
/**
* Controls the RC (Register Clock alias Chip Select) pin of a SPI port
* \param[in] spi SPI number (0 or 1)
* \param[in] pin_value 0 or 1
* \return 0 if no error
*/
int32_t PIOS_SPI_RC_PinSet(uint32_t spi_id, uint32_t slave_id, uint8_t pin_value)
{
struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id;
bool valid = PIOS_SPI_validate(spi_dev);
PIOS_Assert(valid)
PIOS_Assert(slave_id <= spi_dev->cfg->slave_count)
/* XXX multi-slave support? */
if (pin_value) {
GPIO_SetBits(spi_dev->cfg->ssel[slave_id].gpio, spi_dev->cfg->ssel[slave_id].init.GPIO_Pin);
} else {
GPIO_ResetBits(spi_dev->cfg->ssel[slave_id].gpio, spi_dev->cfg->ssel[slave_id].init.GPIO_Pin);
}
return 0;
}
/**
* Transfers a byte to SPI output and reads back the return value from SPI input
* \param[in] spi SPI number (0 or 1)
* \param[in] b the byte which should be transfered
*/
int32_t PIOS_SPI_TransferByte(uint32_t spi_id, uint8_t b)
{
struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id;
bool valid = PIOS_SPI_validate(spi_dev);
PIOS_Assert(valid)
uint8_t rx_byte;
/* Make sure the RXNE flag is cleared by reading the DR register */
SPI_ReceiveData8(spi_dev->cfg->regs);
/* Wait until the TXE goes high */
while (SPI_I2S_GetFlagStatus(spi_dev->cfg->regs, SPI_I2S_FLAG_TXE) == RESET) {
;
}
/* Start the transfer */
SPI_SendData8(spi_dev->cfg->regs, b);
/* Wait until there is a byte to read */
while (SPI_I2S_GetFlagStatus(spi_dev->cfg->regs, SPI_I2S_FLAG_RXNE) == RESET) {
;
}
/* Read the rx'd byte */
rx_byte = SPI_ReceiveData8(spi_dev->cfg->regs);
/* Wait until the TXE goes high */
while (!(spi_dev->cfg->regs->SR & SPI_I2S_FLAG_TXE)) {
;
}
/* Wait for SPI transfer to have fully completed */
while (spi_dev->cfg->regs->SR & SPI_I2S_FLAG_BSY) {
;
}
/* Return received byte */
return rx_byte;
}
/**
* Transfers a block of bytes via PIO.
*
* \param[in] spi_id SPI device handle
* \param[in] send_buffer pointer to buffer which should be sent.<BR>
* If NULL, 0xff (all-one) will be sent.
* \param[in] receive_buffer pointer to buffer which should get the received values.<BR>
* If NULL, received bytes will be discarded.
* \param[in] len number of bytes which should be transfered
* \return >= 0 if no error during transfer
* \return -1 if disabled SPI port selected
*/
static int32_t PIOS_SPI_TransferBlock_PIO(struct pios_spi_dev *spi_dev, const uint8_t *send_buffer, uint8_t *receive_buffer, uint16_t len, __attribute__((unused)) void *callback)
{
uint8_t b;
while (len--) {
/* get the byte to send */
b = send_buffer ? *(send_buffer++) : 0xff;
/* Wait until the TXE goes high */
while (SPI_I2S_GetFlagStatus(spi_dev->cfg->regs, SPI_I2S_FLAG_TXE) == RESET) {
;
}
/* Start the transfer */
SPI_SendData8(spi_dev->cfg->regs, b);
/* Wait until there is a byte to read */
while (SPI_I2S_GetFlagStatus(spi_dev->cfg->regs, SPI_I2S_FLAG_RXNE) == RESET) {
;
}
/* Read the rx'd byte */
b = SPI_ReceiveData8(spi_dev->cfg->regs);
/* save the received byte */
if (receive_buffer) {
*(receive_buffer++) = b;
}
}
/* Wait for SPI transfer to have fully completed */
while (spi_dev->cfg->regs->SR & SPI_I2S_FLAG_BSY) {
;
}
return 0;
}
/**
* Transfers a block of bytes via DMA.
* \param[in] spi SPI number (0 or 1)
* \param[in] send_buffer pointer to buffer which should be sent.<BR>
* If NULL, 0xff (all-one) will be sent.
* \param[in] receive_buffer pointer to buffer which should get the received values.<BR>
* If NULL, received bytes will be discarded.
* \param[in] len number of bytes which should be transfered
* \param[in] callback pointer to callback function which will be executed
* from DMA channel interrupt once the transfer is finished.
* If NULL, no callback function will be used, and PIOS_SPI_TransferBlock() will
* block until the transfer is finished.
* \return >= 0 if no error during transfer
* \return -1 if disabled SPI port selected
* \return -3 if function has been called during an ongoing DMA transfer
*/
static int32_t PIOS_SPI_TransferBlock_DMA(struct pios_spi_dev *spi_dev, const uint8_t *send_buffer, uint8_t *receive_buffer, uint16_t len, void *callback)
{
DMA_InitTypeDef dma_init;
/* Exit if ongoing transfer */
if (DMA_GetCurrDataCounter(spi_dev->cfg->dma.rx.channel)) {
return -3;
}
/* Disable the SPI peripheral */
SPI_Cmd(spi_dev->cfg->regs, DISABLE);
/* Disable the DMA channels */
DMA_Cmd(spi_dev->cfg->dma.rx.channel, DISABLE);
DMA_Cmd(spi_dev->cfg->dma.tx.channel, DISABLE);
/* Set callback function */
spi_dev->callback = callback;
/*
* Configure Rx channel
*/
/* Start with the default configuration for this peripheral */
dma_init = spi_dev->cfg->dma.rx.init;
if (receive_buffer != NULL) {
/* Enable memory addr. increment - bytes written into receive buffer */
dma_init.DMA_MemoryBaseAddr = (uint32_t)receive_buffer;
dma_init.DMA_MemoryInc = DMA_MemoryInc_Enable;
} else {
/* Disable memory addr. increment - bytes written into dummy buffer */
spi_dev->rx_dummy_byte = 0xFF;
dma_init.DMA_MemoryBaseAddr = (uint32_t)&spi_dev->rx_dummy_byte;
dma_init.DMA_MemoryInc = DMA_MemoryInc_Disable;
}
if (spi_dev->cfg->use_crc) {
/* Make sure the CRC error flag is cleared before we start */
SPI_I2S_ClearFlag(spi_dev->cfg->regs, SPI_FLAG_CRCERR);
}
dma_init.DMA_BufferSize = len;
DMA_Init(spi_dev->cfg->dma.rx.channel, &(dma_init));
/*
* Configure Tx channel
*/
/* Start with the default configuration for this peripheral */
dma_init = spi_dev->cfg->dma.tx.init;
if (send_buffer != NULL) {
/* Enable memory addr. increment - bytes written into receive buffer */
dma_init.DMA_MemoryBaseAddr = (uint32_t)send_buffer;
dma_init.DMA_MemoryInc = DMA_MemoryInc_Enable;
} else {
/* Disable memory addr. increment - bytes written into dummy buffer */
spi_dev->tx_dummy_byte = 0xFF;
dma_init.DMA_MemoryBaseAddr = (uint32_t)&spi_dev->tx_dummy_byte;
dma_init.DMA_MemoryInc = DMA_MemoryInc_Disable;
}
if (spi_dev->cfg->use_crc) {
/* The last byte of the payload will be replaced with the CRC8 */
dma_init.DMA_BufferSize = len - 1;
} else {
dma_init.DMA_BufferSize = len;
}
DMA_Init(spi_dev->cfg->dma.tx.channel, &(dma_init));
/* Enable DMA interrupt if callback function active */
DMA_ITConfig(spi_dev->cfg->dma.rx.channel, DMA_IT_TC, (callback != NULL) ? ENABLE : DISABLE);
/* Flush out the CRC registers */
SPI_CalculateCRC(spi_dev->cfg->regs, DISABLE);
(void)SPI_GetCRC(spi_dev->cfg->regs, SPI_CRC_Rx);
SPI_I2S_ClearFlag(spi_dev->cfg->regs, SPI_FLAG_CRCERR);
/* Make sure to flush out the receive buffer */
(void)SPI_I2S_ReceiveData16(spi_dev->cfg->regs);
if (spi_dev->cfg->use_crc) {
/* Need a 0->1 transition to reset the CRC logic */
SPI_CalculateCRC(spi_dev->cfg->regs, ENABLE);
}
/* Start DMA transfers */
DMA_Cmd(spi_dev->cfg->dma.rx.channel, ENABLE);
DMA_Cmd(spi_dev->cfg->dma.tx.channel, ENABLE);
/* Reenable the SPI device */
SPI_Cmd(spi_dev->cfg->regs, ENABLE);
if (callback) {
/* User has requested a callback, don't wait for the transfer to complete. */
return 0;
}
/* Wait until all bytes have been transmitted/received */
while (DMA_GetCurrDataCounter(spi_dev->cfg->dma.rx.channel)) {
;
}
/* Wait for the final bytes of the transfer to complete, including CRC byte(s). */
while (!(SPI_I2S_GetFlagStatus(spi_dev->cfg->regs, SPI_I2S_FLAG_TXE))) {
;
}
/* Wait for the final bytes of the transfer to complete, including CRC byte(s). */
while (SPI_I2S_GetFlagStatus(spi_dev->cfg->regs, SPI_I2S_FLAG_BSY)) {
;
}
/* Check the CRC on the transfer if enabled. */
if (spi_dev->cfg->use_crc) {
/* Check the SPI CRC error flag */
if (SPI_I2S_GetFlagStatus(spi_dev->cfg->regs, SPI_FLAG_CRCERR)) {
return -4;
}
}
/* No error */
return 0;
}
int32_t PIOS_SPI_TransferBlock(uint32_t spi_id, const uint8_t *send_buffer, uint8_t *receive_buffer, uint16_t len, void *callback)
{
struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id;
bool valid = PIOS_SPI_validate(spi_dev);
PIOS_Assert(valid)
if ((len > SPI_MAX_BLOCK_PIO) && spi_dev->cfg->dma.rx.channel && spi_dev->cfg->dma.tx.channel) {
return PIOS_SPI_TransferBlock_DMA(spi_dev, send_buffer, receive_buffer, len, callback);
}
return PIOS_SPI_TransferBlock_PIO(spi_dev, send_buffer, receive_buffer, len, callback);
}
/**
* Check if a transfer is in progress
* \param[in] spi SPI number (0 or 1)
* \return >= 0 if no transfer is in progress
* \return -1 if disabled SPI port selected
* \return -2 if unsupported SPI port selected
* \return -3 if function has been called during an ongoing DMA transfer
*/
int32_t PIOS_SPI_Busy(uint32_t spi_id)
{
struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id;
bool valid = PIOS_SPI_validate(spi_dev);
PIOS_Assert(valid)
/* DMA buffer has data or SPI transmit register not empty or SPI is busy*/
if (DMA_GetCurrDataCounter(spi_dev->cfg->dma.rx.channel) ||
!SPI_I2S_GetFlagStatus(spi_dev->cfg->regs, SPI_I2S_FLAG_TXE) ||
SPI_I2S_GetFlagStatus(spi_dev->cfg->regs, SPI_I2S_FLAG_BSY)) {
return -3;
}
return 0;
}
void PIOS_SPI_SetPrescalar(uint32_t spi_id, uint32_t prescaler)
{
struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id;
bool valid = PIOS_SPI_validate(spi_dev);
PIOS_Assert(valid);
PIOS_Assert(IS_SPI_BAUDRATE_PRESCALER(prescaler));
spi_dev->cfg->regs->CR1 = (spi_dev->cfg->regs->CR1 & ~0x0038) | prescaler;
}
void PIOS_SPI_IRQ_Handler(uint32_t spi_id)
{
struct pios_spi_dev *spi_dev = (struct pios_spi_dev *)spi_id;
bool valid = PIOS_SPI_validate(spi_dev);
PIOS_Assert(valid)
DMA_ClearFlag(spi_dev->cfg->dma.irq.flags);
/* Wait for the final bytes of the transfer to complete, including CRC byte(s). */
while (!(SPI_I2S_GetFlagStatus(spi_dev->cfg->regs, SPI_I2S_FLAG_TXE))) {
;
}
/* Wait for the final bytes of the transfer to complete, including CRC byte(s). */
while (SPI_I2S_GetFlagStatus(spi_dev->cfg->regs, SPI_I2S_FLAG_BSY)) {
;
}
if (spi_dev->callback != NULL) {
bool crc_ok = true;
uint8_t crc_val;
if (SPI_I2S_GetFlagStatus(spi_dev->cfg->regs, SPI_FLAG_CRCERR)) {
crc_ok = false;
SPI_I2S_ClearFlag(spi_dev->cfg->regs, SPI_FLAG_CRCERR);
}
crc_val = SPI_GetCRC(spi_dev->cfg->regs, SPI_CRC_Rx);
spi_dev->callback(crc_ok, crc_val);
}
}
#endif /* PIOS_INCLUDE_SPI */
/**
* @}
* @}
*/

View File

@ -0,0 +1,287 @@
/**
******************************************************************************
* @addtogroup PIOS PIOS Core hardware abstraction layer
* @{
* @addtogroup PIOS_SYS System Functions
* @brief PIOS System Initialization code
* @{
*
* @file pios_sys.c
* @author Michael Smith Copyright (C) 2011
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
* @author Tau Labs, http://taulabs.org, Copyright (C) 2012-2014
* @brief Sets up basic STM32 system hardware, functions are called from Main.
* @see The GNU Public License (GPL) Version 3
*
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* Project Includes */
#include "pios.h"
#if defined(PIOS_INCLUDE_SYS)
#define MEM8(addr) (*((volatile uint8_t *)(addr)))
/* Private Function Prototypes */
static void NVIC_Configuration(void);
/**
* Initialises all system peripherals
*/
void PIOS_SYS_Init(void)
{
/* Setup STM32 system (RCC, clock, PLL and Flash configuration) - CMSIS Function */
SystemInit();
SystemCoreClockUpdate(); /* update SystemCoreClock for use elsewhere */
/*
* @todo might make sense to fetch the bus clocks and save them somewhere to avoid
* having to use the clunky get-all-clocks API everytime we need one.
*/
/* Initialise Basic NVIC */
/* do this early to ensure that we take exceptions in the right place */
NVIC_Configuration();
/* Init the delay system */
PIOS_DELAY_Init();
/*
* Turn on all the peripheral clocks.
* Micromanaging clocks makes no sense given the power situation in the system, so
* light up everything we might reasonably use here and just leave it on.
*/
RCC_AHBPeriphClockCmd(
RCC_AHBPeriph_GPIOA |
RCC_AHBPeriph_GPIOB |
RCC_AHBPeriph_GPIOC |
RCC_AHBPeriph_GPIOD |
RCC_AHBPeriph_GPIOE |
RCC_AHBPeriph_GPIOF |
RCC_AHBPeriph_TS |
RCC_AHBPeriph_CRC |
RCC_AHBPeriph_FLITF |
RCC_AHBPeriph_SRAM |
RCC_AHBPeriph_DMA2 |
RCC_AHBPeriph_DMA1 |
RCC_AHBPeriph_ADC34 |
RCC_AHBPeriph_ADC12 |
0, ENABLE);
RCC_APB1PeriphClockCmd(
RCC_APB1Periph_TIM2 |
RCC_APB1Periph_TIM3 |
RCC_APB1Periph_TIM4 |
RCC_APB1Periph_TIM6 |
RCC_APB1Periph_TIM7 |
RCC_APB1Periph_WWDG |
RCC_APB1Periph_SPI2 |
RCC_APB1Periph_SPI3 |
RCC_APB1Periph_USART2 |
RCC_APB1Periph_USART3 |
RCC_APB1Periph_UART4 |
RCC_APB1Periph_UART5 |
RCC_APB1Periph_I2C1 |
RCC_APB1Periph_I2C2 |
RCC_APB1Periph_USB |
RCC_APB1Periph_CAN1 |
RCC_APB1Periph_PWR |
RCC_APB1Periph_DAC |
0, ENABLE);
RCC_APB2PeriphClockCmd(
RCC_APB2Periph_TIM1 |
RCC_APB2Periph_TIM8 |
RCC_APB2Periph_TIM15 |
RCC_APB2Periph_TIM16 |
RCC_APB2Periph_TIM17 |
RCC_APB2Periph_USART1 |
RCC_APB2Periph_SPI1 |
RCC_APB2Periph_SYSCFG |
0, ENABLE);
/*
* Configure all pins as input / pullup to avoid issues with
* uncommitted pins, excepting special-function pins that we need to
* remain as-is.
*/
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; // default is un-pulled input
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;
#if (PIOS_USB_ENABLED)
GPIO_InitStructure.GPIO_Pin &= ~(GPIO_Pin_11 | GPIO_Pin_12); // leave USB D+/D- alone
#endif
GPIO_InitStructure.GPIO_Pin &= ~(GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15); // leave JTAG pins alone
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_Init(GPIOD, &GPIO_InitStructure);
GPIO_Init(GPIOE, &GPIO_InitStructure);
GPIO_Init(GPIOF, &GPIO_InitStructure);
}
/**
* Shutdown PIOS and reset the microcontroller:<BR>
* <UL>
* <LI>Disable all RTOS tasks
* <LI>Disable all interrupts
* <LI>Turn off all board LEDs
* <LI>Reset STM32
* </UL>
* \return < 0 if reset failed
*/
int32_t PIOS_SYS_Reset(void)
{
// disable all interrupts
PIOS_IRQ_Disable();
// turn off all board LEDs
#ifdef PIOS_INCLUDE_LED
# ifdef PIOS_LED_HEARTBEAT
PIOS_LED_Off(PIOS_LED_HEARTBEAT);
# endif /* PIOS_LED_HEARTBEAT */
# ifdef PIOS_LED_ALARM
PIOS_LED_Off(PIOS_LED_ALARM);
# endif /* PIOS_LED_ALARM */
# ifdef PIOS_BUZZER_ALARM
PIOS_LED_Off(PIOS_BUZZER_ALARM);
# endif /* PIOS_BUZZER_ALARM */
#endif /* PIOS_INCLUDE_LED */
/* XXX F10x port resets most (but not all) peripherals ... do we care? */
/* Reset STM32 */
NVIC_SystemReset();
while (1) {
;
}
/* We will never reach this point */
return -1;
}
/**
* Returns the serial number as byte array
* param[out] pointer to a byte array which can store at least 12 bytes
* (12 bytes returned for STM32)
* return < 0 if feature not supported
*/
int32_t PIOS_SYS_SerialNumberGetBinary(uint8_t *array)
{
int i;
/* Stored in the so called "electronic signature" */
for (i = 0; i < PIOS_SYS_SERIAL_NUM_BINARY_LEN; ++i) {
uint8_t b = MEM8(0x1ffff7ac + i);
array[i] = b;
}
/* No error */
return 0;
}
/**
* Returns the serial number as a string
* param[out] str pointer to a string which can store at least 32 digits + zero terminator!
* (24 digits returned for STM32)
* return < 0 if feature not supported
*/
int32_t PIOS_SYS_SerialNumberGet(char *str)
{
int i;
/* Stored in the so called "electronic signature" */
for (i = 0; i < PIOS_SYS_SERIAL_NUM_ASCII_LEN; ++i) {
uint8_t b = MEM8(0x1ffff7ac + (i / 2));
if (!(i & 1)) {
b >>= 4;
}
b &= 0x0f;
str[i] = ((b > 9) ? ('A' - 10) : '0') + b;
}
str[i] = '\0';
/* No error */
return 0;
}
/**
* Configures Vector Table base location and SysTick
*/
static void NVIC_Configuration(void)
{
/* Set the Vector Table base address as specified in .ld file */
extern void *pios_isr_vector_table_base;
NVIC_SetVectorTable((uint32_t)&pios_isr_vector_table_base, 0x0);
/* 4 bits for Interrupt priorities so no sub priorities */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
/* Configure HCLK clock as SysTick clock source. */
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);
}
#ifdef USE_FULL_ASSERT
/**
* Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* \param[in] file pointer to the source file name
* \param[in] line assert_param error line source number
* \retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* When serial debugging is implemented, use something like this. */
/* printf("Wrong parameters value: file %s on line %d\r\n", file, line); */
/* Setup the LEDs to Alternate */
#if defined(PIOS_LED_HEARTBEAT)
PIOS_LED_On(PIOS_LED_HEARTBEAT);
#endif /* PIOS_LED_HEARTBEAT */
#if defined(PIOS_LED_ALARM)
PIOS_LED_Off(PIOS_LED_ALARM);
#endif /* PIOS_LED_ALARM */
/* Infinite loop */
while (1) {
#if defined(PIOS_LED_HEARTBEAT)
PIOS_LED_Toggle(PIOS_LED_HEARTBEAT);
#endif /* PIOS_LED_HEARTBEAT */
#if defined(PIOS_LED_ALARM)
PIOS_LED_Toggle(PIOS_LED_ALARM);
#endif /* PIOS_LED_ALARM */
for (int i = 0; i < 1000000; i++) {
;
}
}
}
#endif /* ifdef USE_FULL_ASSERT */
#endif /* if defined(PIOS_INCLUDE_SYS) */
/**
* @}
* @}
*/

View File

@ -0,0 +1,401 @@
/**
******************************************************************************
* @addtogroup PIOS PIOS Core hardware abstraction layer
* @{
* @addtogroup PIOS_TIM Timer Functions
* @brief PIOS Timer control code
* @{
*
* @file pios_tim.c
* @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017.
* The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
* @brief Sets up timers and ways to register callbacks on them
* @see The GNU Public License (GPL) Version 3
*
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "pios.h"
#ifdef PIOS_INCLUDE_TIM
#include "pios_tim_priv.h"
enum pios_tim_dev_magic {
PIOS_TIM_DEV_MAGIC = 0x87654098,
};
struct pios_tim_dev {
enum pios_tim_dev_magic magic;
const struct pios_tim_channel *channels;
uint8_t num_channels;
const struct pios_tim_callbacks *callbacks;
uint32_t context;
};
#if 0
static bool PIOS_TIM_validate(struct pios_tim_dev *tim_dev)
{
return tim_dev->magic == PIOS_TIM_DEV_MAGIC;
}
#endif
#if defined(PIOS_INCLUDE_FREERTOS) && 0
static struct pios_tim_dev *PIOS_TIM_alloc(void)
{
struct pios_tim_dev *tim_dev;
tim_dev = (struct pios_tim_dev *)pios_malloc(sizeof(*tim_dev));
if (!tim_dev) {
return NULL;
}
tim_dev->magic = PIOS_TIM_DEV_MAGIC;
return tim_dev;
}
#else
static struct pios_tim_dev pios_tim_devs[PIOS_TIM_MAX_DEVS];
static uint8_t pios_tim_num_devs;
static struct pios_tim_dev *PIOS_TIM_alloc(void)
{
struct pios_tim_dev *tim_dev;
if (pios_tim_num_devs >= PIOS_TIM_MAX_DEVS) {
return NULL;
}
tim_dev = &pios_tim_devs[pios_tim_num_devs++];
tim_dev->magic = PIOS_TIM_DEV_MAGIC;
return tim_dev;
}
#endif /* if defined(PIOS_INCLUDE_FREERTOS) && 0 */
int32_t PIOS_TIM_InitClock(const struct pios_tim_clock_cfg *cfg)
{
PIOS_DEBUG_Assert(cfg);
/* Configure the dividers for this timer */
TIM_TimeBaseInit(cfg->timer, (TIM_TimeBaseInitTypeDef *)cfg->time_base_init);
/* Configure internal timer clocks */
TIM_InternalClockConfig(cfg->timer);
/* Enable timers */
TIM_Cmd(cfg->timer, ENABLE);
/* Enable Interrupts */
NVIC_Init((NVIC_InitTypeDef *)&cfg->irq.init);
// Advanced timers TIM1 & TIM8 need special handling:
// There are up to 4 separate interrupts handlers for each advanced timer, but
// pios_tim_clock_cfg has provision for only one irq init, so we take care here
// to enable additional irq channels that we intend to use.
if (cfg->timer == TIM1) {
NVIC_InitTypeDef init = cfg->irq.init;
init.NVIC_IRQChannel = TIM1_UP_TIM16_IRQn;
NVIC_Init(&init);
} else if (cfg->timer == TIM8) {
NVIC_InitTypeDef init = cfg->irq.init;
init.NVIC_IRQChannel = TIM8_UP_IRQn;
NVIC_Init(&init);
}
return 0;
}
int32_t PIOS_TIM_InitChannels(uint32_t *tim_id, const struct pios_tim_channel *channels, uint8_t num_channels, const struct pios_tim_callbacks *callbacks, uint32_t context)
{
PIOS_Assert(channels);
PIOS_Assert(num_channels);
struct pios_tim_dev *tim_dev;
tim_dev = (struct pios_tim_dev *)PIOS_TIM_alloc();
if (!tim_dev) {
goto out_fail;
}
/* Bind the configuration to the device instance */
tim_dev->channels = channels;
tim_dev->num_channels = num_channels;
tim_dev->callbacks = callbacks;
tim_dev->context = context;
/* Configure the pins */
for (uint8_t i = 0; i < num_channels; i++) {
const struct pios_tim_channel *chan = &(channels[i]);
GPIO_Init(chan->pin.gpio, (GPIO_InitTypeDef *)&chan->pin.init);
if (chan->remap) {
GPIO_PinAFConfig(chan->pin.gpio, chan->pin.pin_source, chan->remap);
}
}
*tim_id = (uint32_t)tim_dev;
return 0;
out_fail:
return -1;
}
static void PIOS_TIM_generic_irq_handler(TIM_TypeDef *timer)
{
/* Check for an overflow event on this timer */
bool overflow_event = 0;
uint16_t overflow_count = false;
if (TIM_GetITStatus(timer, TIM_IT_Update) == SET) {
TIM_ClearITPendingBit(timer, TIM_IT_Update);
overflow_count = timer->ARR;
overflow_event = true;
}
/* Iterate over all registered clients of the TIM layer to find channels on this timer */
for (uint8_t i = 0; i < pios_tim_num_devs; i++) {
const struct pios_tim_dev *tim_dev = &pios_tim_devs[i];
if (!tim_dev->channels || tim_dev->num_channels == 0) {
/* No channels to process on this client */
continue;
}
for (uint8_t j = 0; j < tim_dev->num_channels; j++) {
const struct pios_tim_channel *chan = &tim_dev->channels[j];
if (chan->timer != timer) {
/* channel is not on this timer */
continue;
}
/* Figure out which interrupt bit we should be looking at */
uint16_t timer_it;
switch (chan->timer_chan) {
case TIM_Channel_1:
timer_it = TIM_IT_CC1;
break;
case TIM_Channel_2:
timer_it = TIM_IT_CC2;
break;
case TIM_Channel_3:
timer_it = TIM_IT_CC3;
break;
case TIM_Channel_4:
timer_it = TIM_IT_CC4;
break;
default:
PIOS_Assert(0);
break;
}
bool edge_event;
uint16_t edge_count;
if (TIM_GetITStatus(chan->timer, timer_it) == SET) {
TIM_ClearITPendingBit(chan->timer, timer_it);
/* Read the current counter */
switch (chan->timer_chan) {
case TIM_Channel_1:
edge_count = TIM_GetCapture1(chan->timer);
break;
case TIM_Channel_2:
edge_count = TIM_GetCapture2(chan->timer);
break;
case TIM_Channel_3:
edge_count = TIM_GetCapture3(chan->timer);
break;
case TIM_Channel_4:
edge_count = TIM_GetCapture4(chan->timer);
break;
default:
PIOS_Assert(0);
break;
}
edge_event = true;
} else {
edge_event = false;
edge_count = 0;
}
if (!tim_dev->callbacks) {
/* No callbacks registered, we're done with this channel */
continue;
}
/* Generate the appropriate callbacks */
if (overflow_event & edge_event) {
/*
* When both edge and overflow happen in the same interrupt, we
* need a heuristic to determine the order of the edge and overflow
* events so that the callbacks happen in the right order. If we
* get the order wrong, our pulse width calculations could be off by up
* to ARR ticks. That could be bad.
*
* Heuristic: If the edge_count is < 32 ticks above zero then we assume the
* edge happened just after the overflow.
*/
if (edge_count < 32) {
/* Call the overflow callback first */
if (tim_dev->callbacks->overflow) {
(*tim_dev->callbacks->overflow)((uint32_t)tim_dev,
tim_dev->context,
j,
overflow_count);
}
/* Call the edge callback second */
if (tim_dev->callbacks->edge) {
(*tim_dev->callbacks->edge)((uint32_t)tim_dev,
tim_dev->context,
j,
edge_count);
}
} else {
/* Call the edge callback first */
if (tim_dev->callbacks->edge) {
(*tim_dev->callbacks->edge)((uint32_t)tim_dev,
tim_dev->context,
j,
edge_count);
}
/* Call the overflow callback second */
if (tim_dev->callbacks->overflow) {
(*tim_dev->callbacks->overflow)((uint32_t)tim_dev,
tim_dev->context,
j,
overflow_count);
}
}
} else if (overflow_event && tim_dev->callbacks->overflow) {
(*tim_dev->callbacks->overflow)((uint32_t)tim_dev,
tim_dev->context,
j,
overflow_count);
} else if (edge_event && tim_dev->callbacks->edge) {
(*tim_dev->callbacks->edge)((uint32_t)tim_dev,
tim_dev->context,
j,
edge_count);
}
}
}
}
/* Bind Interrupt Handlers
*
* Map all valid TIM IRQs to the common interrupt handler
* and give it enough context to properly demux the various timers
*/
void TIM1_CC_IRQHandler(void) __attribute__((alias("PIOS_TIM_1_CC_irq_handler")));
static void PIOS_TIM_1_CC_irq_handler(void)
{
PIOS_TIM_generic_irq_handler(TIM1);
}
// The rest of TIM1 interrupts are overlapped
void TIM1_BRK_TIM15_IRQHandler(void) __attribute__((alias("PIOS_TIM_1_BRK_TIM_15_irq_handler")));
static void PIOS_TIM_1_BRK_TIM_15_irq_handler(void)
{
if (TIM_GetITStatus(TIM1, TIM_IT_Break)) {
PIOS_TIM_generic_irq_handler(TIM1);
} else if (TIM_GetITStatus(TIM15, TIM_IT_Update | TIM_IT_CC1 | TIM_IT_CC2 | TIM_IT_CC3 | TIM_IT_CC4 | TIM_IT_COM | TIM_IT_Trigger | TIM_IT_Break)) {
PIOS_TIM_generic_irq_handler(TIM15);
}
}
void TIM1_UP_TIM16_IRQHandler(void) __attribute__((alias("PIOS_TIM_1_UP_TIM_16_irq_handler")));
static void PIOS_TIM_1_UP_TIM_16_irq_handler(void)
{
if (TIM_GetITStatus(TIM1, TIM_IT_Update)) {
PIOS_TIM_generic_irq_handler(TIM1);
} else if (TIM_GetITStatus(TIM16, TIM_IT_Update | TIM_IT_CC1 | TIM_IT_CC2 | TIM_IT_CC3 | TIM_IT_CC4 | TIM_IT_COM | TIM_IT_Trigger | TIM_IT_Break)) {
PIOS_TIM_generic_irq_handler(TIM16);
}
}
void TIM1_TRG_COM_TIM17_IRQHandler(void) __attribute__((alias("PIOS_TIM_1_TRG_COM_TIM_17_irq_handler")));
static void PIOS_TIM_1_TRG_COM_TIM_17_irq_handler(void)
{
if (TIM_GetITStatus(TIM1, TIM_IT_Trigger | TIM_IT_COM)) {
PIOS_TIM_generic_irq_handler(TIM1);
} else if (TIM_GetITStatus(TIM17, TIM_IT_Update | TIM_IT_CC1 | TIM_IT_CC2 | TIM_IT_CC3 | TIM_IT_CC4 | TIM_IT_COM | TIM_IT_Trigger | TIM_IT_Break)) {
PIOS_TIM_generic_irq_handler(TIM17);
}
}
void TIM2_IRQHandler(void) __attribute__((alias("PIOS_TIM_2_irq_handler")));
static void PIOS_TIM_2_irq_handler(void)
{
PIOS_TIM_generic_irq_handler(TIM2);
}
void TIM3_IRQHandler(void) __attribute__((alias("PIOS_TIM_3_irq_handler")));
static void PIOS_TIM_3_irq_handler(void)
{
PIOS_TIM_generic_irq_handler(TIM3);
}
void TIM4_IRQHandler(void) __attribute__((alias("PIOS_TIM_4_irq_handler")));
static void PIOS_TIM_4_irq_handler(void)
{
PIOS_TIM_generic_irq_handler(TIM4);
}
void TIM6_DAC_IRQHandler(void) __attribute__((alias("PIOS_TIM_6_DAC_irq_handler")));
static void PIOS_TIM_6_DAC_irq_handler(void)
{
// What about DAC irq?
if (TIM_GetITStatus(TIM6, TIM_IT_Update | TIM_IT_CC1 | TIM_IT_CC2 | TIM_IT_CC3 | TIM_IT_CC4 | TIM_IT_COM | TIM_IT_Trigger | TIM_IT_Break)) {
PIOS_TIM_generic_irq_handler(TIM6);
}
}
void TIM7_IRQHandler(void) __attribute__((alias("PIOS_TIM_7_irq_handler")));
static void PIOS_TIM_7_irq_handler(void)
{
PIOS_TIM_generic_irq_handler(TIM7);
}
void TIM8_CC_IRQHandler(void) __attribute__((alias("PIOS_TIM_8_CC_irq_handler")));
static void PIOS_TIM_8_CC_irq_handler(void)
{
PIOS_TIM_generic_irq_handler(TIM8);
}
void TIM8_BRK_IRQHandler(void) __attribute__((alias("PIOS_TIM_8_BRK_irq_handler")));
static void PIOS_TIM_8_BRK_irq_handler(void)
{
PIOS_TIM_generic_irq_handler(TIM8);
}
void TIM8_UP_IRQHandler(void) __attribute__((alias("PIOS_TIM_8_UP_irq_handler")));
static void PIOS_TIM_8_UP_irq_handler(void)
{
PIOS_TIM_generic_irq_handler(TIM8);
}
void TIM8_TRG_COM_IRQHandler(void) __attribute__((alias("PIOS_TIM_8_TRG_COM_irq_handler")));
static void PIOS_TIM_8_TRG_COM_irq_handler(void)
{
PIOS_TIM_generic_irq_handler(TIM8);
}
#endif /* PIOS_INCLUDE_TIM */

View File

@ -0,0 +1,601 @@
/**
******************************************************************************
* @addtogroup PIOS PIOS Core hardware abstraction layer
* @{
* @addtogroup PIOS_USART USART Functions
* @brief PIOS interface for USART port
* @{
*
* @file pios_usart.c
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @brief USART commands. Inits USARTs, controls USARTs & Interupt handlers. (STM32 dependent)
* @see The GNU Public License (GPL) Version 3
*
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "pios.h"
#ifdef PIOS_INCLUDE_USART
#include <pios_usart_priv.h>
/* Provide a COM driver */
static void PIOS_USART_ChangeBaud(uint32_t usart_id, uint32_t baud);
static void PIOS_USART_ChangeConfig(uint32_t usart_id, enum PIOS_COM_Word_Length word_len, enum PIOS_COM_Parity parity, enum PIOS_COM_StopBits stop_bits, uint32_t baud_rate);
static void PIOS_USART_RegisterRxCallback(uint32_t usart_id, pios_com_callback rx_in_cb, uint32_t context);
static void PIOS_USART_RegisterTxCallback(uint32_t usart_id, pios_com_callback tx_out_cb, uint32_t context);
static void PIOS_USART_TxStart(uint32_t usart_id, uint16_t tx_bytes_avail);
static void PIOS_USART_RxStart(uint32_t usart_id, uint16_t rx_bytes_avail);
static int32_t PIOS_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param);
const struct pios_com_driver pios_usart_com_driver = {
.set_baud = PIOS_USART_ChangeBaud,
.set_config = PIOS_USART_ChangeConfig,
.tx_start = PIOS_USART_TxStart,
.rx_start = PIOS_USART_RxStart,
.bind_tx_cb = PIOS_USART_RegisterTxCallback,
.bind_rx_cb = PIOS_USART_RegisterRxCallback,
.ioctl = PIOS_USART_Ioctl,
};
enum pios_usart_dev_magic {
PIOS_USART_DEV_MAGIC = 0x11223344,
};
struct pios_usart_dev {
enum pios_usart_dev_magic magic;
const struct pios_usart_cfg *cfg;
USART_InitTypeDef init;
pios_com_callback rx_in_cb;
uint32_t rx_in_context;
pios_com_callback tx_out_cb;
uint32_t tx_out_context;
bool config_locked;
uint32_t rx_dropped;
uint8_t irq_channel;
};
static bool PIOS_USART_validate(struct pios_usart_dev *usart_dev)
{
return usart_dev->magic == PIOS_USART_DEV_MAGIC;
}
static int32_t PIOS_USART_SetIrqPrio(struct pios_usart_dev *usart_dev, uint8_t irq_prio)
{
NVIC_InitTypeDef init = {
.NVIC_IRQChannel = usart_dev->irq_channel,
.NVIC_IRQChannelPreemptionPriority = irq_prio,
.NVIC_IRQChannelCmd = ENABLE,
};
NVIC_Init(&init);
return 0;
}
#if defined(PIOS_INCLUDE_FREERTOS)
static struct pios_usart_dev *PIOS_USART_alloc(void)
{
struct pios_usart_dev *usart_dev;
usart_dev = (struct pios_usart_dev *)pios_malloc(sizeof(struct pios_usart_dev));
if (!usart_dev) {
return NULL;
}
memset(usart_dev, 0, sizeof(struct pios_usart_dev));
usart_dev->magic = PIOS_USART_DEV_MAGIC;
return usart_dev;
}
#else
static struct pios_usart_dev pios_usart_devs[PIOS_USART_MAX_DEVS];
static uint8_t pios_usart_num_devs;
static struct pios_usart_dev *PIOS_USART_alloc(void)
{
struct pios_usart_dev *usart_dev;
if (pios_usart_num_devs >= PIOS_USART_MAX_DEVS) {
return NULL;
}
usart_dev = &pios_usart_devs[pios_usart_num_devs++];
memset(usart_dev, 0, sizeof(struct pios_usart_dev));
usart_dev->magic = PIOS_USART_DEV_MAGIC;
return usart_dev;
}
#endif /* if defined(PIOS_INCLUDE_FREERTOS) */
/* Bind Interrupt Handlers
*
* Map all valid USART IRQs to the common interrupt handler
* and provide storage for a 32-bit device id IRQ to map
* each physical IRQ to a specific registered device instance.
*/
static void PIOS_USART_generic_irq_handler(uint32_t usart_id);
static uint32_t PIOS_USART_1_id;
void USART1_EXTI25_IRQHandler(void) __attribute__((alias("PIOS_USART_1_irq_handler")));
static void PIOS_USART_1_irq_handler(void)
{
PIOS_USART_generic_irq_handler(PIOS_USART_1_id);
}
static uint32_t PIOS_USART_2_id;
void USART2_EXTI26_IRQHandler(void) __attribute__((alias("PIOS_USART_2_irq_handler")));
static void PIOS_USART_2_irq_handler(void)
{
PIOS_USART_generic_irq_handler(PIOS_USART_2_id);
}
static uint32_t PIOS_USART_3_id;
void USART3_EXTI28_IRQHandler(void) __attribute__((alias("PIOS_USART_3_irq_handler")));
static void PIOS_USART_3_irq_handler(void)
{
PIOS_USART_generic_irq_handler(PIOS_USART_3_id);
}
static uint32_t PIOS_UART_4_id;
void UART4_EXTI34_IRQHandler(void) __attribute__((alias("PIOS_UART_4_irq_handler")));
static void PIOS_UART_4_irq_handler(void)
{
PIOS_USART_generic_irq_handler(PIOS_UART_4_id);
}
static uint32_t PIOS_UART_5_id;
void UART5_EXTI35_IRQHandler(void) __attribute__((alias("PIOS_UART_5_irq_handler")));
static void PIOS_UART_5_irq_handler(void)
{
PIOS_USART_generic_irq_handler(PIOS_UART_5_id);
}
/**
* Initialise a single USART device
*/
int32_t PIOS_USART_Init(uint32_t *usart_id, const struct pios_usart_cfg *cfg)
{
PIOS_DEBUG_Assert(usart_id);
PIOS_DEBUG_Assert(cfg);
uint32_t *local_id;
uint8_t irq_channel;
switch ((uint32_t)cfg->regs) {
case (uint32_t)USART1:
local_id = &PIOS_USART_1_id;
irq_channel = USART1_IRQn;
break;
case (uint32_t)USART2:
local_id = &PIOS_USART_2_id;
irq_channel = USART2_IRQn;
break;
case (uint32_t)USART3:
local_id = &PIOS_USART_3_id;
irq_channel = USART3_IRQn;
break;
case (uint32_t)UART4:
local_id = &PIOS_UART_4_id;
irq_channel = UART4_IRQn;
break;
case (uint32_t)UART5:
local_id = &PIOS_UART_5_id;
irq_channel = UART5_IRQn;
break;
default:
goto out_fail;
}
if (*local_id) {
/* this port is already open */
*usart_id = *local_id;
return 0;
}
struct pios_usart_dev *usart_dev;
usart_dev = (struct pios_usart_dev *)PIOS_USART_alloc();
if (!usart_dev) {
goto out_fail;
}
/* Bind the configuration to the device instance */
usart_dev->cfg = cfg;
usart_dev->irq_channel = irq_channel;
/* Set some sane defaults */
USART_StructInit(&usart_dev->init);
/* We will set modes later, depending on installed callbacks */
usart_dev->init.USART_Mode = 0;
/* DTR handling? */
*usart_id = (uint32_t)usart_dev;
*local_id = (uint32_t)usart_dev;
PIOS_USART_SetIrqPrio(usart_dev, PIOS_IRQ_PRIO_MID);
/* Disable overrun detection */
USART_OverrunDetectionConfig(usart_dev->cfg->regs, USART_OVRDetection_Disable);
return 0;
out_fail:
return -1;
}
static void PIOS_USART_Setup(struct pios_usart_dev *usart_dev)
{
/* Configure RX GPIO */
if ((usart_dev->init.USART_Mode & USART_Mode_Rx) && (usart_dev->cfg->rx.gpio)) {
if (usart_dev->cfg->remap) {
GPIO_PinAFConfig(usart_dev->cfg->rx.gpio,
usart_dev->cfg->rx.pin_source,
usart_dev->cfg->remap);
}
GPIO_Init(usart_dev->cfg->rx.gpio, (GPIO_InitTypeDef *)&usart_dev->cfg->rx.init);
USART_ITConfig(usart_dev->cfg->regs, USART_IT_RXNE, ENABLE);
}
/* Configure TX GPIO */
if ((usart_dev->init.USART_Mode & USART_Mode_Tx) && usart_dev->cfg->tx.gpio) {
if (usart_dev->cfg->remap) {
GPIO_PinAFConfig(usart_dev->cfg->tx.gpio,
usart_dev->cfg->tx.pin_source,
usart_dev->cfg->remap);
}
GPIO_Init(usart_dev->cfg->tx.gpio, (GPIO_InitTypeDef *)&usart_dev->cfg->tx.init);
}
/* Write new configuration */
#if 0
const char *dbg_parity = "?";
switch (usart_dev->init.USART_Parity) {
case USART_Parity_No: dbg_parity = "N"; break;
case USART_Parity_Even: dbg_parity = "E"; break;
case USART_Parity_Odd: dbg_parity = "O"; break;
}
const char *dbg_mode = "???";
switch (usart_dev->init.USART_Mode) {
case USART_Mode_Rx: dbg_mode = "rx"; break;
case USART_Mode_Tx: dbg_mode = "tx"; break;
case USART_Mode_Rx | USART_Mode_Tx: dbg_mode = "rx_tx"; break;
}
const char *dbg_flow_control = "???";
switch (usart_dev->init.USART_HardwareFlowControl) {
case USART_HardwareFlowControl_None: dbg_flow_control = "none"; break;
case USART_HardwareFlowControl_RTS: dbg_flow_control = "rts"; break;
case USART_HardwareFlowControl_CTS: dbg_flow_control = "cts"; break;
case USART_HardwareFlowControl_RTS_CTS: dbg_flow_control = "rts_cts"; break;
}
const char *dbg_stop_bits = "???";
switch (usart_dev->init.USART_StopBits) {
case USART_StopBits_1: dbg_stop_bits = "1"; break;
case USART_StopBits_2: dbg_stop_bits = "2"; break;
case USART_StopBits_1_5: dbg_stop_bits = "1.5"; break;
}
DEBUG_PRINTF(0, "PIOS_USART_Setup: 0x%08x %u %u%s%s mode=%s flow_control=%s\r\n",
(uint32_t)usart_dev,
usart_dev->init.USART_BaudRate,
usart_dev->init.USART_WordLength == USART_WordLength_8b ? 8 : 9,
dbg_parity,
dbg_stop_bits,
dbg_mode,
dbg_flow_control);
#endif /* if 0 */
{ // fix parity stuff
USART_InitTypeDef init = usart_dev->init;
if ((init.USART_Parity != USART_Parity_No) && (init.USART_WordLength == USART_WordLength_8b)) {
init.USART_WordLength = USART_WordLength_9b;
}
USART_Init(usart_dev->cfg->regs, &init);
}
/*
* Re enable USART.
*/
USART_Cmd(usart_dev->cfg->regs, ENABLE);
}
static void PIOS_USART_RxStart(uint32_t usart_id, __attribute__((unused)) uint16_t rx_bytes_avail)
{
struct pios_usart_dev *usart_dev = (struct pios_usart_dev *)usart_id;
bool valid = PIOS_USART_validate(usart_dev);
PIOS_Assert(valid);
USART_ITConfig(usart_dev->cfg->regs, USART_IT_RXNE, ENABLE);
}
static void PIOS_USART_TxStart(uint32_t usart_id, __attribute__((unused)) uint16_t tx_bytes_avail)
{
struct pios_usart_dev *usart_dev = (struct pios_usart_dev *)usart_id;
bool valid = PIOS_USART_validate(usart_dev);
PIOS_Assert(valid);
USART_ITConfig(usart_dev->cfg->regs, USART_IT_TXE, ENABLE);
}
/**
* Changes the baud rate of the USART peripheral without re-initialising.
* \param[in] usart_id USART name (GPS, TELEM, AUX)
* \param[in] baud Requested baud rate
*/
static void PIOS_USART_ChangeBaud(uint32_t usart_id, uint32_t baud)
{
struct pios_usart_dev *usart_dev = (struct pios_usart_dev *)usart_id;
bool valid = PIOS_USART_validate(usart_dev);
PIOS_Assert(valid);
if (usart_dev->config_locked) {
return;
}
usart_dev->init.USART_BaudRate = baud;
PIOS_USART_Setup(usart_dev);
}
/**
* Changes configuration of the USART peripheral without re-initialising.
* \param[in] usart_id USART name (GPS, TELEM, AUX)
* \param[in] word_len Requested word length
* \param[in] stop_bits Requested stop bits
* \param[in] parity Requested parity
*
*/
static void PIOS_USART_ChangeConfig(uint32_t usart_id,
enum PIOS_COM_Word_Length word_len,
enum PIOS_COM_Parity parity,
enum PIOS_COM_StopBits stop_bits,
uint32_t baud_rate)
{
struct pios_usart_dev *usart_dev = (struct pios_usart_dev *)usart_id;
bool valid = PIOS_USART_validate(usart_dev);
PIOS_Assert(valid);
if (usart_dev->config_locked) {
return;
}
switch (word_len) {
case PIOS_COM_Word_length_8b:
usart_dev->init.USART_WordLength = USART_WordLength_8b;
break;
case PIOS_COM_Word_length_9b:
usart_dev->init.USART_WordLength = USART_WordLength_9b;
break;
default:
break;
}
switch (stop_bits) {
case PIOS_COM_StopBits_1:
usart_dev->init.USART_StopBits = USART_StopBits_1;
break;
case PIOS_COM_StopBits_1_5:
usart_dev->init.USART_StopBits = USART_StopBits_1_5;
break;
case PIOS_COM_StopBits_2:
usart_dev->init.USART_StopBits = USART_StopBits_2;
break;
default:
break;
}
switch (parity) {
case PIOS_COM_Parity_No:
usart_dev->init.USART_Parity = USART_Parity_No;
break;
case PIOS_COM_Parity_Even:
usart_dev->init.USART_Parity = USART_Parity_Even;
break;
case PIOS_COM_Parity_Odd:
usart_dev->init.USART_Parity = USART_Parity_Odd;
break;
default:
break;
}
if (baud_rate) {
usart_dev->init.USART_BaudRate = baud_rate;
}
PIOS_USART_Setup(usart_dev);
}
static void PIOS_USART_RegisterRxCallback(uint32_t usart_id, pios_com_callback rx_in_cb, uint32_t context)
{
struct pios_usart_dev *usart_dev = (struct pios_usart_dev *)usart_id;
bool valid = PIOS_USART_validate(usart_dev);
PIOS_Assert(valid);
/*
* Order is important in these assignments since ISR uses _cb
* field to determine if it's ok to dereference _cb and _context
*/
usart_dev->rx_in_context = context;
usart_dev->rx_in_cb = rx_in_cb;
usart_dev->init.USART_Mode |= USART_Mode_Rx;
PIOS_USART_Setup(usart_dev);
}
static void PIOS_USART_RegisterTxCallback(uint32_t usart_id, pios_com_callback tx_out_cb, uint32_t context)
{
struct pios_usart_dev *usart_dev = (struct pios_usart_dev *)usart_id;
bool valid = PIOS_USART_validate(usart_dev);
PIOS_Assert(valid);
/*
* Order is important in these assignments since ISR uses _cb
* field to determine if it's ok to dereference _cb and _context
*/
usart_dev->tx_out_context = context;
usart_dev->tx_out_cb = tx_out_cb;
usart_dev->init.USART_Mode |= USART_Mode_Tx;
PIOS_USART_Setup(usart_dev);
}
static void PIOS_USART_generic_irq_handler(uint32_t usart_id)
{
struct pios_usart_dev *usart_dev = (struct pios_usart_dev *)usart_id;
bool valid = PIOS_USART_validate(usart_dev);
PIOS_Assert(valid);
/* Force read of dr after sr to make sure to clear error flags */
volatile uint16_t sr = usart_dev->cfg->regs->ISR;
volatile uint8_t dr = usart_dev->cfg->regs->RDR;
/* Check if RXNE flag is set */
bool rx_need_yield = false;
if (sr & USART_ISR_RXNE) {
uint8_t byte = dr;
if (usart_dev->rx_in_cb) {
uint16_t rc;
rc = (usart_dev->rx_in_cb)(usart_dev->rx_in_context, &byte, 1, NULL, &rx_need_yield);
if (rc < 1) {
/* Lost bytes on rx */
usart_dev->rx_dropped += 1;
}
}
}
/* Check if TXE flag is set */
bool tx_need_yield = false;
if (sr & USART_ISR_TXE) {
if (usart_dev->tx_out_cb) {
uint8_t b;
uint16_t bytes_to_send;
bytes_to_send = (usart_dev->tx_out_cb)(usart_dev->tx_out_context, &b, 1, NULL, &tx_need_yield);
if (bytes_to_send > 0) {
/* Send the byte we've been given */
usart_dev->cfg->regs->TDR = b;
} else {
/* No bytes to send, disable TXE interrupt */
USART_ITConfig(usart_dev->cfg->regs, USART_IT_TXE, DISABLE);
}
} else {
/* No bytes to send, disable TXE interrupt */
USART_ITConfig(usart_dev->cfg->regs, USART_IT_TXE, DISABLE);
}
}
#if defined(PIOS_INCLUDE_FREERTOS)
if (rx_need_yield || tx_need_yield) {
vPortYield();
}
#endif /* PIOS_INCLUDE_FREERTOS */
}
static int32_t PIOS_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param)
{
struct pios_usart_dev *usart_dev = (struct pios_usart_dev *)usart_id;
bool valid = PIOS_USART_validate(usart_dev);
PIOS_Assert(valid);
/* some sort of locking would be great to have */
uint32_t cr1_ue = usart_dev->cfg->regs->CR1 & USART_CR1_UE;
switch (ctl) {
case PIOS_IOCTL_USART_SET_IRQ_PRIO:
return PIOS_USART_SetIrqPrio(usart_dev, *(uint8_t *)param);
case PIOS_IOCTL_USART_SET_INVERTED:
{
enum PIOS_USART_Inverted inverted = *(enum PIOS_USART_Inverted *)param;
usart_dev->cfg->regs->CR1 &= ~((uint32_t)USART_CR1_UE);
if (usart_dev->cfg->rx.gpio != 0) {
GPIO_InitTypeDef gpioInit = usart_dev->cfg->rx.init;
gpioInit.GPIO_PuPd = (inverted & PIOS_USART_Inverted_Rx) ? GPIO_PuPd_DOWN : GPIO_PuPd_UP;
GPIO_Init(usart_dev->cfg->rx.gpio, &gpioInit);
USART_InvPinCmd(usart_dev->cfg->regs, USART_InvPin_Rx, (inverted & PIOS_USART_Inverted_Rx) ? ENABLE : DISABLE);
}
if (usart_dev->cfg->tx.gpio != 0) {
USART_InvPinCmd(usart_dev->cfg->regs, USART_InvPin_Tx, (inverted & PIOS_USART_Inverted_Tx) ? ENABLE : DISABLE);
}
}
break;
case PIOS_IOCTL_USART_SET_SWAPPIN:
usart_dev->cfg->regs->CR1 &= ~((uint32_t)USART_CR1_UE);
USART_SWAPPinCmd(usart_dev->cfg->regs, *(bool *)param ? ENABLE : DISABLE);
break;
case PIOS_IOCTL_USART_SET_HALFDUPLEX:
usart_dev->cfg->regs->CR1 &= ~((uint32_t)USART_CR1_UE);
USART_HalfDuplexCmd(usart_dev->cfg->regs, *(bool *)param ? ENABLE : DISABLE);
break;
case PIOS_IOCTL_USART_GET_DSMBIND:
case PIOS_IOCTL_USART_GET_RXGPIO:
*(struct stm32_gpio *)param = usart_dev->cfg->rx;
break;
case PIOS_IOCTL_USART_GET_TXGPIO:
*(struct stm32_gpio *)param = usart_dev->cfg->tx;
break;
case PIOS_IOCTL_USART_LOCK_CONFIG:
usart_dev->config_locked = *(bool *)param;
break;
default:
return -1;
}
usart_dev->cfg->regs->CR1 |= cr1_ue;
return 0;
}
#endif /* PIOS_INCLUDE_USART */
/**
* @}
* @}
*/

View File

@ -0,0 +1,335 @@
/**
******************************************************************************
* @addtogroup PIOS PIOS Core hardware abstraction layer
* @{
* @addtogroup PIOS_USB USB Setup Functions
* @brief PIOS USB device implementation
* @{
*
* @file pios_usb.c
* @author The LibrePilot Project, http://www.librepilot.org (C) 2017.
* Tau Labs, http://taulabs.org, Copyright (C) 2012-2013
* The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @brief USB device functions (STM32 dependent code)
* @see The GNU Public License (GPL) Version 3
*
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* Project Includes */
#include "pios.h"
#if defined(PIOS_INCLUDE_USB)
#include "usb_lib.h"
#include "pios_usb_board_data.h"
#include "pios_usb.h"
#include "pios_usb_priv.h"
/* Rx/Tx status */
static bool transfer_possible = false;
#ifdef PIOS_INCLUDE_FREERTOS
struct {
void (*callback)(bool connected, uint32_t context);
uint32_t context;
} connectionState_cb_list[3];
#endif
/* USB activity detection */
static volatile bool sof_seen_since_reset = false;
enum pios_usb_dev_magic {
PIOS_USB_DEV_MAGIC = 0x17365904,
};
struct pios_usb_dev {
enum pios_usb_dev_magic magic;
const struct pios_usb_cfg *cfg;
};
#ifdef PIOS_INCLUDE_FREERTOS
static void raiseConnectionStateCallback(bool connected);
#endif
/**
* @brief Validate the usb device structure
* @returns 0 if valid device or -1 otherwise
*/
static int32_t PIOS_USB_validate(struct pios_usb_dev *usb_dev)
{
if (usb_dev == NULL) {
return -1;
}
if (usb_dev->magic != PIOS_USB_DEV_MAGIC) {
return -1;
}
return 0;
}
#ifdef PIOS_INCLUDE_FREERTOS
static struct pios_usb_dev *PIOS_USB_alloc(void)
{
struct pios_usb_dev *usb_dev;
usb_dev = (struct pios_usb_dev *)pios_malloc(sizeof(*usb_dev));
if (!usb_dev) {
return NULL;
}
usb_dev->magic = PIOS_USB_DEV_MAGIC;
return usb_dev;
}
#else
static struct pios_usb_dev pios_usb_devs[PIOS_USB_MAX_DEVS];
static uint8_t pios_usb_num_devs;
static struct pios_usb_dev *PIOS_USB_alloc(void)
{
struct pios_usb_dev *usb_dev;
if (pios_usb_num_devs >= PIOS_USB_MAX_DEVS) {
return NULL;
}
usb_dev = &pios_usb_devs[pios_usb_num_devs++];
usb_dev->magic = PIOS_USB_DEV_MAGIC;
return usb_dev;
}
#endif /* ifdef PIOS_INCLUDE_FREERTOS */
/**
* Initialises USB COM layer
* \return < 0 if initialisation failed
* \note Applications shouldn't call this function directly, instead please use \ref PIOS_COM layer functions
*/
static uint32_t pios_usb_com_id;
int32_t PIOS_USB_Init(uint32_t *usb_id, const struct pios_usb_cfg *cfg)
{
PIOS_Assert(usb_id);
PIOS_Assert(cfg);
struct pios_usb_dev *usb_dev;
usb_dev = (struct pios_usb_dev *)PIOS_USB_alloc();
if (!usb_dev) {
goto out_fail;
}
/* Bind the configuration to the device instance */
usb_dev->cfg = cfg;
PIOS_USB_Reenumerate();
/*
* This is a horrible hack to make this available to
* the interrupt callbacks. This should go away ASAP.
*/
pios_usb_com_id = (uintptr_t)usb_dev;
/* Enable the USB Interrupts */
NVIC_Init((NVIC_InitTypeDef *)&usb_dev->cfg->irq.init);
/* Configure USB D-/D+ (DM/DP) pins */
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource11, GPIO_AF_14);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource12, GPIO_AF_14);
/* Configure VBUS sense pin */
if (usb_dev->cfg->vsense.gpio) {
GPIO_Init(usb_dev->cfg->vsense.gpio, (GPIO_InitTypeDef *)&usb_dev->cfg->vsense.init);
}
/* Select USBCLK source */
RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_1Div5);
/* Enable the USB clock */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USB, ENABLE);
USB_Init();
USB_SIL_Init();
*usb_id = (uintptr_t)usb_dev;
return 0; /* No error */
out_fail:
return -1;
}
/**
* This function is called by the USB driver on cable connection/disconnection
* \param[in] connected connection status (1 if connected)
* \return < 0 on errors
* \note Applications shouldn't call this function directly, instead please use \ref PIOS_COM layer functions
*/
int32_t PIOS_USB_ChangeConnectionState(bool Connected)
{
// In all cases: re-initialise USB HID driver
if (Connected) {
transfer_possible = true;
// TODO: Check SetEPRxValid(ENDP1);
#if defined(USB_LED_ON)
USB_LED_ON; // turn the USB led on
#endif
} else {
// Cable disconnected: disable transfers
transfer_possible = false;
#if defined(USB_LED_OFF)
USB_LED_OFF; // turn the USB led off
#endif
}
#ifdef PIOS_INCLUDE_FREERTOS
raiseConnectionStateCallback(Connected);
#endif
return 0;
}
int32_t PIOS_USB_Reenumerate()
{
/* Force USB reset and power-down (this will also release the USB pins for direct GPIO control) */
_SetCNTR(CNTR_FRES | CNTR_PDWN);
/* Using a "dirty" method to force a re-enumeration: */
/* Force DPM (Pin PA12) low for ca. 10 mS before USB Tranceiver will be enabled */
/* This overrules the external Pull-Up at PA12, and at least Windows & MacOS will enumerate again */
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
PIOS_DELAY_WaitmS(50);
/* Release power-down, still hold reset */
_SetCNTR(CNTR_PDWN);
PIOS_DELAY_WaituS(5);
/* CNTR_FRES = 0 */
_SetCNTR(0);
/* Clear pending interrupts */
_SetISTR(0);
/* set back to alternate function */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Configure USB clock */
/* USBCLK = PLLCLK / 1.5 */
RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_1Div5);
/* Enable USB clock */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USB, ENABLE);
return 0;
}
bool PIOS_USB_CableConnected(__attribute__((unused)) uint8_t id)
{
struct pios_usb_dev *usb_dev = (struct pios_usb_dev *)pios_usb_com_id;
if (PIOS_USB_validate(usb_dev) != 0) {
return false;
}
// If board is configured to have a VSENSE pin, use that
if (usb_dev->cfg->vsense.gpio != NULL) {
return GPIO_ReadInputDataBit(usb_dev->cfg->vsense.gpio, usb_dev->cfg->vsense.init.GPIO_Pin) == Bit_SET;
}
return sof_seen_since_reset;
}
/**
* This function returns the connection status of the USB HID interface
* \return 1: interface available
* \return 0: interface not available
* \note Applications shouldn't call this function directly, instead please use \ref PIOS_COM layer functions
*/
bool PIOS_USB_CheckAvailable(uint32_t id)
{
struct pios_usb_dev *usb_dev = (struct pios_usb_dev *)pios_usb_com_id;
if (PIOS_USB_validate(usb_dev) != 0) {
return false;
}
return PIOS_USB_CableConnected(id) && transfer_possible;
}
void SOF_Callback(void)
{
sof_seen_since_reset = true;
}
void SUSP_Callback(void)
{
sof_seen_since_reset = false;
}
#ifdef PIOS_INCLUDE_FREERTOS
void PIOS_USB_RegisterConnectionStateCallback(void (*connectionStateCallback)(bool connected, uint32_t context), uint32_t context)
{
PIOS_Assert(connectionStateCallback);
for (uint32_t i = 0; i < NELEMENTS(connectionState_cb_list); i++) {
if (connectionState_cb_list[i].callback == NULL) {
connectionState_cb_list[i].callback = connectionStateCallback;
connectionState_cb_list[i].context = context;
return;
}
}
PIOS_Assert(0);
}
static void raiseConnectionStateCallback(bool connected)
{
uint32_t i = 0;
while (i < NELEMENTS(connectionState_cb_list) && connectionState_cb_list[i].callback != NULL) {
connectionState_cb_list[i].callback(connected, connectionState_cb_list[i].context);
i++;
}
}
#else /* PIOS_INCLUDE_FREERTOS */
void PIOS_USB_RegisterConnectionStateCallback(__attribute__((unused)) void (*connectionStateCallback)(bool connected, uint32_t context), __attribute__((unused)) uint32_t context)
{}
#endif /* PIOS_INCLUDE_FREERTOS */
#endif /* if defined(PIOS_INCLUDE_USB) */
/**
* @}
* @}
*/

View File

@ -0,0 +1,526 @@
/**
******************************************************************************
* @addtogroup PIOS PIOS Core hardware abstraction layer
* @{
* @addtogroup PIOS_USB_COM USB COM Functions
* @brief PIOS USB COM implementation for CDC interfaces
* @notes This implements a CDC Serial Port
* @{
*
* @file pios_usb_cdc.c
* @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017.
* The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @brief USB COM functions (STM32 dependent code)
* @see The GNU Public License (GPL) Version 3
*
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "pios.h"
#ifdef PIOS_INCLUDE_USB_CDC
#include "pios_usb_cdc_priv.h"
#include "pios_usb_board_data.h" /* PIOS_BOARD_*_DATA_LENGTH */
/* STM32 USB Library Definitions */
#include "usb_lib.h"
static void PIOS_USB_CDC_RegisterTxCallback(uint32_t usbcdc_id, pios_com_callback tx_out_cb, uint32_t context);
static void PIOS_USB_CDC_RegisterRxCallback(uint32_t usbcdc_id, pios_com_callback rx_in_cb, uint32_t context);
static void PIOS_USB_CDC_RegisterBaudRateCallback(uint32_t usbcdc_id, pios_com_callback_baud_rate baud_rate_cb, uint32_t context);
static void PIOS_USB_CDC_RegisterAvailableCallback(uint32_t usbcdc_id, pios_com_callback_available baud_rate_cb, uint32_t context);
static void PIOS_USB_CDC_ChangeConnectionState(bool connected, uint32_t usbcdc_id);
static void PIOS_USB_CDC_TxStart(uint32_t usbcdc_id, uint16_t tx_bytes_avail);
static void PIOS_USB_CDC_RxStart(uint32_t usbcdc_id, uint16_t rx_bytes_avail);
static uint32_t PIOS_USB_CDC_Available(uint32_t usbcdc_id);
const struct pios_com_driver pios_usb_cdc_com_driver = {
.tx_start = PIOS_USB_CDC_TxStart,
.rx_start = PIOS_USB_CDC_RxStart,
.bind_tx_cb = PIOS_USB_CDC_RegisterTxCallback,
.bind_rx_cb = PIOS_USB_CDC_RegisterRxCallback,
.bind_baud_rate_cb = PIOS_USB_CDC_RegisterBaudRateCallback,
.available = PIOS_USB_CDC_Available,
.bind_available_cb = PIOS_USB_CDC_RegisterAvailableCallback,
};
enum pios_usb_cdc_dev_magic {
PIOS_USB_CDC_DEV_MAGIC = 0xAABBCCDD,
};
struct pios_usb_cdc_dev {
enum pios_usb_cdc_dev_magic magic;
const struct pios_usb_cdc_cfg *cfg;
uint32_t lower_id;
pios_com_callback rx_in_cb;
uint32_t rx_in_context;
pios_com_callback tx_out_cb;
uint32_t tx_out_context;
pios_com_callback_baud_rate baud_rate_cb;
uint32_t baud_rate_context;
pios_com_callback_available available_cb;
uint32_t available_context;
uint8_t rx_packet_buffer[PIOS_USB_BOARD_CDC_DATA_LENGTH];
/*
* NOTE: This is -1 as somewhat of a hack. It ensures that we always send packets
* that are strictly < maxPacketSize for this interface which means we never have
* to bother with zero length packets (ZLP).
*/
uint8_t tx_packet_buffer[PIOS_USB_BOARD_CDC_DATA_LENGTH - 1];
uint32_t rx_dropped;
uint32_t rx_oversize;
};
static bool PIOS_USB_CDC_validate(struct pios_usb_cdc_dev *usb_cdc_dev)
{
return usb_cdc_dev->magic == PIOS_USB_CDC_DEV_MAGIC;
}
#if defined(PIOS_INCLUDE_FREERTOS)
static struct pios_usb_cdc_dev *PIOS_USB_CDC_alloc(void)
{
struct pios_usb_cdc_dev *usb_cdc_dev;
usb_cdc_dev = (struct pios_usb_cdc_dev *)pios_fastheapmalloc(sizeof(struct pios_usb_cdc_dev));
if (!usb_cdc_dev) {
return NULL;
}
memset(usb_cdc_dev, 0, sizeof(struct pios_usb_cdc_dev));
usb_cdc_dev->magic = PIOS_USB_CDC_DEV_MAGIC;
return usb_cdc_dev;
}
#else
static struct pios_usb_cdc_dev pios_usb_cdc_devs[PIOS_USB_CDC_MAX_DEVS];
static uint8_t pios_usb_cdc_num_devs;
static struct pios_usb_cdc_dev *PIOS_USB_CDC_alloc(void)
{
struct pios_usb_cdc_dev *usb_cdc_dev;
if (pios_usb_cdc_num_devs >= PIOS_USB_CDC_MAX_DEVS) {
return NULL;
}
usb_cdc_dev = &pios_usb_cdc_devs[pios_usb_cdc_num_devs++];
memset(usb_cdc_dev, 0, sizeof(struct pios_usb_cdc_dev));
usb_cdc_dev->magic = PIOS_USB_CDC_DEV_MAGIC;
return usb_cdc_dev;
}
#endif /* if defined(PIOS_INCLUDE_FREERTOS) */
static void PIOS_USB_CDC_DATA_EP_IN_Callback(void);
static void PIOS_USB_CDC_DATA_EP_OUT_Callback(void);
static void PIOS_USB_CDC_CTRL_EP_IN_Callback(void);
static uint32_t pios_usb_cdc_id;
/* Need a better way to pull these in */
extern void(*pEpInt_IN[7]) (void);
extern void(*pEpInt_OUT[7]) (void);
int32_t PIOS_USB_CDC_Init(uint32_t *usbcdc_id, const struct pios_usb_cdc_cfg *cfg, uint32_t lower_id)
{
PIOS_Assert(usbcdc_id);
PIOS_Assert(cfg);
struct pios_usb_cdc_dev *usb_cdc_dev;
usb_cdc_dev = (struct pios_usb_cdc_dev *)PIOS_USB_CDC_alloc();
if (!usb_cdc_dev) {
goto out_fail;
}
/* Bind the configuration to the device instance */
usb_cdc_dev->cfg = cfg;
usb_cdc_dev->lower_id = lower_id;
pios_usb_cdc_id = (uint32_t)usb_cdc_dev;
/* Bind lower level callbacks into the USB infrastructure */
pEpInt_OUT[cfg->ctrl_tx_ep - 1] = PIOS_USB_CDC_CTRL_EP_IN_Callback;
pEpInt_IN[cfg->data_tx_ep - 1] = PIOS_USB_CDC_DATA_EP_IN_Callback;
pEpInt_OUT[cfg->data_rx_ep - 1] = PIOS_USB_CDC_DATA_EP_OUT_Callback;
PIOS_USB_RegisterConnectionStateCallback(PIOS_USB_CDC_ChangeConnectionState, (uint32_t)usb_cdc_dev);
*usbcdc_id = (uint32_t)usb_cdc_dev;
return 0;
out_fail:
return -1;
}
static void PIOS_USB_CDC_RegisterRxCallback(uint32_t usbcdc_id, pios_com_callback rx_in_cb, uint32_t context)
{
struct pios_usb_cdc_dev *usb_cdc_dev = (struct pios_usb_cdc_dev *)usbcdc_id;
bool valid = PIOS_USB_CDC_validate(usb_cdc_dev);
PIOS_Assert(valid);
/*
* Order is important in these assignments since ISR uses _cb
* field to determine if it's ok to dereference _cb and _context
*/
usb_cdc_dev->rx_in_context = context;
usb_cdc_dev->rx_in_cb = rx_in_cb;
}
static void PIOS_USB_CDC_RegisterTxCallback(uint32_t usbcdc_id, pios_com_callback tx_out_cb, uint32_t context)
{
struct pios_usb_cdc_dev *usb_cdc_dev = (struct pios_usb_cdc_dev *)usbcdc_id;
bool valid = PIOS_USB_CDC_validate(usb_cdc_dev);
PIOS_Assert(valid);
/*
* Order is important in these assignments since ISR uses _cb
* field to determine if it's ok to dereference _cb and _context
*/
usb_cdc_dev->tx_out_context = context;
usb_cdc_dev->tx_out_cb = tx_out_cb;
}
static void PIOS_USB_CDC_RxStart(uint32_t usbcdc_id, uint16_t rx_bytes_avail)
{
struct pios_usb_cdc_dev *usb_cdc_dev = (struct pios_usb_cdc_dev *)usbcdc_id;
bool valid = PIOS_USB_CDC_validate(usb_cdc_dev);
PIOS_Assert(valid);
if (!PIOS_USB_CheckAvailable(usb_cdc_dev->lower_id)) {
return;
}
// If endpoint was stalled and there is now space make it valid
PIOS_IRQ_Disable();
if ((GetEPRxStatus(usb_cdc_dev->cfg->data_rx_ep) != EP_RX_VALID) &&
(rx_bytes_avail >= sizeof(usb_cdc_dev->rx_packet_buffer))) {
SetEPRxStatus(usb_cdc_dev->cfg->data_rx_ep, EP_RX_VALID);
}
PIOS_IRQ_Enable();
}
static void PIOS_USB_CDC_SendData(struct pios_usb_cdc_dev *usb_cdc_dev)
{
uint16_t bytes_to_tx;
if (!usb_cdc_dev->tx_out_cb) {
return;
}
bool need_yield = false;
bytes_to_tx = (usb_cdc_dev->tx_out_cb)(usb_cdc_dev->tx_out_context,
usb_cdc_dev->tx_packet_buffer,
sizeof(usb_cdc_dev->tx_packet_buffer),
NULL,
&need_yield);
if (bytes_to_tx == 0) {
return;
}
UserToPMABufferCopy(usb_cdc_dev->tx_packet_buffer,
GetEPTxAddr(usb_cdc_dev->cfg->data_tx_ep),
bytes_to_tx);
SetEPTxCount(usb_cdc_dev->cfg->data_tx_ep, bytes_to_tx);
SetEPTxValid(usb_cdc_dev->cfg->data_tx_ep);
#if defined(PIOS_INCLUDE_FREERTOS)
if (need_yield) {
vPortYield();
}
#endif /* PIOS_INCLUDE_FREERTOS */
}
static void PIOS_USB_CDC_TxStart(uint32_t usbcdc_id, __attribute__((unused)) uint16_t tx_bytes_avail)
{
struct pios_usb_cdc_dev *usb_cdc_dev = (struct pios_usb_cdc_dev *)usbcdc_id;
bool valid = PIOS_USB_CDC_validate(usb_cdc_dev);
PIOS_Assert(valid);
if (!PIOS_USB_CheckAvailable(usb_cdc_dev->lower_id)) {
return;
}
if (GetEPTxStatus(usb_cdc_dev->cfg->data_tx_ep) == EP_TX_VALID) {
/* Endpoint is already transmitting */
return;
}
PIOS_USB_CDC_SendData(usb_cdc_dev);
}
static void PIOS_USB_CDC_DATA_EP_IN_Callback(void)
{
struct pios_usb_cdc_dev *usb_cdc_dev = (struct pios_usb_cdc_dev *)pios_usb_cdc_id;
bool valid = PIOS_USB_CDC_validate(usb_cdc_dev);
PIOS_Assert(valid);
PIOS_USB_CDC_SendData(usb_cdc_dev);
}
static void PIOS_USB_CDC_DATA_EP_OUT_Callback(void)
{
struct pios_usb_cdc_dev *usb_cdc_dev = (struct pios_usb_cdc_dev *)pios_usb_cdc_id;
bool valid = PIOS_USB_CDC_validate(usb_cdc_dev);
PIOS_Assert(valid);
uint32_t DataLength;
/* Get the number of received data on the selected Endpoint */
DataLength = GetEPRxCount(usb_cdc_dev->cfg->data_rx_ep);
if (DataLength > sizeof(usb_cdc_dev->rx_packet_buffer)) {
usb_cdc_dev->rx_oversize++;
DataLength = sizeof(usb_cdc_dev->rx_packet_buffer);
}
/* Use the memory interface function to read from the selected endpoint */
PMAToUserBufferCopy((uint8_t *)usb_cdc_dev->rx_packet_buffer,
GetEPRxAddr(usb_cdc_dev->cfg->data_rx_ep),
DataLength);
if (!usb_cdc_dev->rx_in_cb) {
/* No Rx call back registered, disable the receiver */
SetEPRxStatus(usb_cdc_dev->cfg->data_rx_ep, EP_RX_NAK);
return;
}
uint16_t headroom;
bool need_yield = false;
uint16_t rc;
rc = (usb_cdc_dev->rx_in_cb)(usb_cdc_dev->rx_in_context,
usb_cdc_dev->rx_packet_buffer,
DataLength,
&headroom,
&need_yield);
if (rc < DataLength) {
/* Lost bytes on rx */
usb_cdc_dev->rx_dropped += (DataLength - rc);
}
if (headroom >= sizeof(usb_cdc_dev->rx_packet_buffer)) {
/* We have room for a maximum length message */
SetEPRxStatus(usb_cdc_dev->cfg->data_rx_ep, EP_RX_VALID);
} else {
/* Not enough room left for a message, apply backpressure */
SetEPRxStatus(usb_cdc_dev->cfg->data_rx_ep, EP_RX_NAK);
}
#if defined(PIOS_INCLUDE_FREERTOS)
if (need_yield) {
vPortYield();
}
#endif /* PIOS_INCLUDE_FREERTOS */
}
static uint16_t control_line_state;
RESULT PIOS_USB_CDC_SetControlLineState(void)
{
struct pios_usb_cdc_dev *usb_cdc_dev = (struct pios_usb_cdc_dev *)pios_usb_cdc_id;
bool valid = PIOS_USB_CDC_validate(usb_cdc_dev);
if (!valid) {
/* No CDC interface is configured */
return USB_UNSUPPORT;
}
uint8_t wValue0 = pInformation->USBwValue0;
uint8_t wValue1 = pInformation->USBwValue1;
control_line_state = wValue1 << 8 | wValue0;
return USB_SUCCESS;
}
static uint32_t PIOS_USB_CDC_Available(uint32_t usbcdc_id)
{
struct pios_usb_cdc_dev *usb_cdc_dev = (struct pios_usb_cdc_dev *)usbcdc_id;
bool valid = PIOS_USB_CDC_validate(usb_cdc_dev);
PIOS_Assert(valid);
return PIOS_USB_CheckAvailable(usb_cdc_dev->lower_id) ? COM_AVAILABLE_RXTX : COM_AVAILABLE_NONE;
}
static struct usb_cdc_line_coding line_coding = {
.dwDTERate = htousbl(57600),
.bCharFormat = USB_CDC_LINE_CODING_STOP_1,
.bParityType = USB_CDC_LINE_CODING_PARITY_NONE,
.bDataBits = 8,
};
uint8_t *PIOS_USB_CDC_SetLineCoding(uint16_t Length)
{
struct pios_usb_cdc_dev *usb_cdc_dev = (struct pios_usb_cdc_dev *)pios_usb_cdc_id;
bool valid = PIOS_USB_CDC_validate(usb_cdc_dev);
if (!valid) {
/* No CDC interface is configured */
return NULL;
}
if (Length == 0) {
/* Report the number of bytes we're prepared to consume */
pInformation->Ctrl_Info.Usb_wLength = sizeof(line_coding);
pInformation->Ctrl_Info.Usb_rLength = sizeof(line_coding);
return NULL;
} else {
/* Give out a pointer to the data struct */
return (uint8_t *)&line_coding;
}
}
const uint8_t *PIOS_USB_CDC_GetLineCoding(uint16_t Length)
{
struct pios_usb_cdc_dev *usb_cdc_dev = (struct pios_usb_cdc_dev *)pios_usb_cdc_id;
bool valid = PIOS_USB_CDC_validate(usb_cdc_dev);
if (!valid) {
/* No CDC interface is configured */
return NULL;
}
if (Length == 0) {
pInformation->Ctrl_Info.Usb_wLength = sizeof(line_coding);
return NULL;
} else {
return (uint8_t *)&line_coding;
}
}
struct usb_cdc_serial_state_report uart_state = {
.bmRequestType = 0xA1,
.bNotification = USB_CDC_NOTIFICATION_SERIAL_STATE,
.wValue = 0,
.wIndex = htousbs(1),
.wLength = htousbs(2),
.bmUartState = htousbs(0),
};
static void PIOS_USB_CDC_CTRL_EP_IN_Callback(void)
{
struct pios_usb_cdc_dev *usb_cdc_dev = (struct pios_usb_cdc_dev *)pios_usb_cdc_id;
bool valid = PIOS_USB_CDC_validate(usb_cdc_dev);
PIOS_Assert(valid);
/* Give back UART State Bitmap */
/* UART State Bitmap
* 15-7: reserved
* 6: bOverRun overrun error
* 5: bParity parity error
* 4: bFraming framing error
* 3: bRingSignal RI
* 2: bBreak break reception
* 1: bTxCarrier DSR
* 0: bRxCarrier DCD
*/
uart_state.bmUartState = htousbs(0x0003);
UserToPMABufferCopy((uint8_t *)&uart_state,
GetEPTxAddr(usb_cdc_dev->cfg->ctrl_tx_ep),
sizeof(uart_state));
SetEPTxCount(usb_cdc_dev->cfg->ctrl_tx_ep, PIOS_USB_BOARD_CDC_MGMT_LENGTH);
SetEPTxValid(usb_cdc_dev->cfg->ctrl_tx_ep);
}
static void PIOS_USB_CDC_RegisterBaudRateCallback(uint32_t usbcdc_id, pios_com_callback_baud_rate baud_rate_cb, uint32_t context)
{
struct pios_usb_cdc_dev *usb_cdc_dev = (struct pios_usb_cdc_dev *)usbcdc_id;
bool valid = PIOS_USB_CDC_validate(usb_cdc_dev);
PIOS_Assert(valid);
/*
* Order is important in these assignments since ISR uses _cb
* field to determine if it's ok to dereference _cb and _context
*/
usb_cdc_dev->baud_rate_context = context;
usb_cdc_dev->baud_rate_cb = baud_rate_cb;
}
void PIOS_USB_CDC_SetLineCoding_Completed()
{
struct pios_usb_cdc_dev *usb_cdc_dev = (struct pios_usb_cdc_dev *)pios_usb_cdc_id;
bool valid = PIOS_USB_CDC_validate(usb_cdc_dev);
if (!valid) {
/* No CDC interface is configured */
return;
}
if (usb_cdc_dev->baud_rate_cb) {
usb_cdc_dev->baud_rate_cb(usb_cdc_dev->baud_rate_context, usbltoh(line_coding.dwDTERate));
}
}
static void PIOS_USB_CDC_ChangeConnectionState(__attribute__((unused)) bool connected, uint32_t usbcdc_id)
{
struct pios_usb_cdc_dev *usb_cdc_dev = (struct pios_usb_cdc_dev *)usbcdc_id;
bool valid = PIOS_USB_CDC_validate(usb_cdc_dev);
PIOS_Assert(valid);
if (usb_cdc_dev->available_cb) {
(usb_cdc_dev->available_cb)(usb_cdc_dev->available_context, PIOS_USB_CDC_Available(usbcdc_id));
}
}
static void PIOS_USB_CDC_RegisterAvailableCallback(uint32_t usbcdc_id, pios_com_callback_available available_cb, uint32_t context)
{
struct pios_usb_cdc_dev *usb_cdc_dev = (struct pios_usb_cdc_dev *)usbcdc_id;
bool valid = PIOS_USB_CDC_validate(usb_cdc_dev);
PIOS_Assert(valid);
/*
* Order is important in these assignments since ISR uses _cb
* field to determine if it's ok to dereference _cb and _context
*/
usb_cdc_dev->available_context = context;
usb_cdc_dev->available_cb = available_cb;
}
#endif /* PIOS_INCLUDE_USB_CDC */

View File

@ -0,0 +1,380 @@
/**
******************************************************************************
* @addtogroup PIOS PIOS Core hardware abstraction layer
* @{
* @addtogroup PIOS_USB_HID USB COM Functions
* @brief PIOS USB COM implementation for HID interfaces
* @notes This implements serial emulation over HID reports
* @{
*
* @file pios_usb_hid.c
* @author The LibrePilot Project, htpp://www.librepilot.org Copyright (C) 2017.
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @brief USB COM functions (STM32 dependent code)
* @see The GNU Public License (GPL) Version 3
*
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "pios.h"
#ifdef PIOS_INCLUDE_USB_HID
#include "pios_usb_hid_priv.h"
#include "pios_usb_board_data.h" /* PIOS_BOARD_*_DATA_LENGTH */
/* STM32 USB Library Definitions */
#include "usb_lib.h"
static void PIOS_USB_HID_RegisterTxCallback(uint32_t usbhid_id, pios_com_callback tx_out_cb, uint32_t context);
static void PIOS_USB_HID_RegisterRxCallback(uint32_t usbhid_id, pios_com_callback rx_in_cb, uint32_t context);
static void PIOS_USB_HID_TxStart(uint32_t usbhid_id, uint16_t tx_bytes_avail);
static void PIOS_USB_HID_RxStart(uint32_t usbhid_id, uint16_t rx_bytes_avail);
static uint32_t PIOS_USB_HID_Available(uint32_t usbhid_id);
const struct pios_com_driver pios_usb_hid_com_driver = {
.tx_start = PIOS_USB_HID_TxStart,
.rx_start = PIOS_USB_HID_RxStart,
.bind_tx_cb = PIOS_USB_HID_RegisterTxCallback,
.bind_rx_cb = PIOS_USB_HID_RegisterRxCallback,
.available = PIOS_USB_HID_Available,
};
enum pios_usb_hid_dev_magic {
PIOS_USB_HID_DEV_MAGIC = 0xAA00BB00,
};
struct pios_usb_hid_dev {
enum pios_usb_hid_dev_magic magic;
const struct pios_usb_hid_cfg *cfg;
uint32_t lower_id;
pios_com_callback rx_in_cb;
uint32_t rx_in_context;
pios_com_callback tx_out_cb;
uint32_t tx_out_context;
uint8_t rx_packet_buffer[PIOS_USB_BOARD_HID_DATA_LENGTH];
uint8_t tx_packet_buffer[PIOS_USB_BOARD_HID_DATA_LENGTH];
uint32_t rx_dropped;
uint32_t rx_oversize;
};
static bool PIOS_USB_HID_validate(struct pios_usb_hid_dev *usb_hid_dev)
{
return usb_hid_dev->magic == PIOS_USB_HID_DEV_MAGIC;
}
#ifdef PIOS_INCLUDE_FREERTOS
static struct pios_usb_hid_dev *PIOS_USB_HID_alloc(void)
{
struct pios_usb_hid_dev *usb_hid_dev;
usb_hid_dev = (struct pios_usb_hid_dev *)pios_fastheapmalloc(sizeof(struct pios_usb_hid_dev));
if (!usb_hid_dev) {
return NULL;
}
memset(usb_hid_dev, 0, sizeof(struct pios_usb_hid_dev));
usb_hid_dev->magic = PIOS_USB_HID_DEV_MAGIC;
return usb_hid_dev;
}
#else
static struct pios_usb_hid_dev pios_usb_hid_devs[PIOS_USB_HID_MAX_DEVS];
static uint8_t pios_usb_hid_num_devs;
static struct pios_usb_hid_dev *PIOS_USB_HID_alloc(void)
{
struct pios_usb_hid_dev *usb_hid_dev;
if (pios_usb_hid_num_devs >= PIOS_USB_HID_MAX_DEVS) {
return NULL;
}
usb_hid_dev = &pios_usb_hid_devs[pios_usb_hid_num_devs++];
memset(usb_hid_dev, 0, sizeof(struct pios_usb_hid_dev));
usb_hid_dev->magic = PIOS_USB_HID_DEV_MAGIC;
return usb_hid_dev;
}
#endif /* ifdef PIOS_INCLUDE_FREERTOS */
static void PIOS_USB_HID_EP_IN_Callback(void);
static void PIOS_USB_HID_EP_OUT_Callback(void);
static uint32_t pios_usb_hid_id;
/* Need a better way to pull these in */
extern void(*pEpInt_IN[7]) (void);
extern void(*pEpInt_OUT[7]) (void);
int32_t PIOS_USB_HID_Init(uint32_t *usbhid_id, const struct pios_usb_hid_cfg *cfg, uint32_t lower_id)
{
PIOS_Assert(usbhid_id);
PIOS_Assert(cfg);
struct pios_usb_hid_dev *usb_hid_dev;
usb_hid_dev = (struct pios_usb_hid_dev *)PIOS_USB_HID_alloc();
if (!usb_hid_dev) {
goto out_fail;
}
/* Bind the configuration to the device instance */
usb_hid_dev->cfg = cfg;
usb_hid_dev->lower_id = lower_id;
pios_usb_hid_id = (uint32_t)usb_hid_dev;
/* Bind lower level callbacks into the USB infrastructure */
pEpInt_IN[cfg->data_tx_ep - 1] = PIOS_USB_HID_EP_IN_Callback;
pEpInt_OUT[cfg->data_rx_ep - 1] = PIOS_USB_HID_EP_OUT_Callback;
*usbhid_id = (uint32_t)usb_hid_dev;
return 0;
out_fail:
return -1;
}
static void PIOS_USB_HID_SendReport(struct pios_usb_hid_dev *usb_hid_dev)
{
uint16_t bytes_to_tx;
if (!usb_hid_dev->tx_out_cb) {
return;
}
bool need_yield = false;
#ifdef PIOS_USB_BOARD_BL_HID_HAS_NO_LENGTH_BYTE
bytes_to_tx = (usb_hid_dev->tx_out_cb)(usb_hid_dev->tx_out_context,
&usb_hid_dev->tx_packet_buffer[1],
sizeof(usb_hid_dev->tx_packet_buffer) - 1,
NULL,
&need_yield);
#else
bytes_to_tx = (usb_hid_dev->tx_out_cb)(usb_hid_dev->tx_out_context,
&usb_hid_dev->tx_packet_buffer[2],
sizeof(usb_hid_dev->tx_packet_buffer) - 2,
NULL,
&need_yield);
#endif
if (bytes_to_tx == 0) {
return;
}
/* Always set type as report ID */
usb_hid_dev->tx_packet_buffer[0] = 1;
#ifdef PIOS_USB_BOARD_BL_HID_HAS_NO_LENGTH_BYTE
UserToPMABufferCopy(usb_hid_dev->tx_packet_buffer,
GetEPTxAddr(usb_hid_dev->cfg->data_tx_ep),
bytes_to_tx + 1);
#else
usb_hid_dev->tx_packet_buffer[1] = bytes_to_tx;
UserToPMABufferCopy(usb_hid_dev->tx_packet_buffer,
GetEPTxAddr(usb_hid_dev->cfg->data_tx_ep),
bytes_to_tx + 2);
#endif
/* Is this correct? Why do we always send the whole buffer? */
SetEPTxCount(usb_hid_dev->cfg->data_tx_ep, sizeof(usb_hid_dev->tx_packet_buffer));
SetEPTxValid(usb_hid_dev->cfg->data_tx_ep);
#ifdef PIOS_INCLUDE_FREERTOS
if (need_yield) {
vPortYield();
}
#endif /* PIOS_INCLUDE_FREERTOS */
}
static void PIOS_USB_HID_RxStart(uint32_t usbhid_id, uint16_t rx_bytes_avail)
{
struct pios_usb_hid_dev *usb_hid_dev = (struct pios_usb_hid_dev *)usbhid_id;
bool valid = PIOS_USB_HID_validate(usb_hid_dev);
PIOS_Assert(valid);
if (!PIOS_USB_CheckAvailable(usb_hid_dev->lower_id)) {
return;
}
// If endpoint was stalled and there is now space make it valid
#ifdef PIOS_USB_BOARD_BL_HID_HAS_NO_LENGTH_BYTE
uint16_t max_payload_length = PIOS_USB_BOARD_HID_DATA_LENGTH - 1;
#else
uint16_t max_payload_length = PIOS_USB_BOARD_HID_DATA_LENGTH - 2;
#endif
PIOS_IRQ_Disable();
if ((GetEPRxStatus(usb_hid_dev->cfg->data_rx_ep) != EP_RX_VALID) &&
(rx_bytes_avail >= max_payload_length)) {
SetEPRxStatus(usb_hid_dev->cfg->data_rx_ep, EP_RX_VALID);
}
PIOS_IRQ_Enable();
}
static void PIOS_USB_HID_TxStart(uint32_t usbhid_id, __attribute__((unused)) uint16_t tx_bytes_avail)
{
struct pios_usb_hid_dev *usb_hid_dev = (struct pios_usb_hid_dev *)usbhid_id;
bool valid = PIOS_USB_HID_validate(usb_hid_dev);
PIOS_Assert(valid);
if (!PIOS_USB_CheckAvailable(usb_hid_dev->lower_id)) {
return;
}
if (GetEPTxStatus(usb_hid_dev->cfg->data_tx_ep) == EP_TX_VALID) {
/* Endpoint is already transmitting */
return;
}
PIOS_USB_HID_SendReport(usb_hid_dev);
}
static void PIOS_USB_HID_RegisterRxCallback(uint32_t usbhid_id, pios_com_callback rx_in_cb, uint32_t context)
{
struct pios_usb_hid_dev *usb_hid_dev = (struct pios_usb_hid_dev *)usbhid_id;
bool valid = PIOS_USB_HID_validate(usb_hid_dev);
PIOS_Assert(valid);
/*
* Order is important in these assignments since ISR uses _cb
* field to determine if it's ok to dereference _cb and _context
*/
usb_hid_dev->rx_in_context = context;
usb_hid_dev->rx_in_cb = rx_in_cb;
}
static void PIOS_USB_HID_RegisterTxCallback(uint32_t usbhid_id, pios_com_callback tx_out_cb, uint32_t context)
{
struct pios_usb_hid_dev *usb_hid_dev = (struct pios_usb_hid_dev *)usbhid_id;
bool valid = PIOS_USB_HID_validate(usb_hid_dev);
PIOS_Assert(valid);
/*
* Order is important in these assignments since ISR uses _cb
* field to determine if it's ok to dereference _cb and _context
*/
usb_hid_dev->tx_out_context = context;
usb_hid_dev->tx_out_cb = tx_out_cb;
}
/**
* @brief Callback used to indicate a transmission from device INto host completed
* Checks if any data remains, pads it into HID packet and sends.
*/
static void PIOS_USB_HID_EP_IN_Callback(void)
{
struct pios_usb_hid_dev *usb_hid_dev = (struct pios_usb_hid_dev *)pios_usb_hid_id;
bool valid = PIOS_USB_HID_validate(usb_hid_dev);
PIOS_Assert(valid);
if (!PIOS_USB_CheckAvailable(usb_hid_dev->lower_id)) {
return;
}
PIOS_USB_HID_SendReport(usb_hid_dev);
}
/**
* EP1 OUT Callback Routine
*/
static void PIOS_USB_HID_EP_OUT_Callback(void)
{
struct pios_usb_hid_dev *usb_hid_dev = (struct pios_usb_hid_dev *)pios_usb_hid_id;
bool valid = PIOS_USB_HID_validate(usb_hid_dev);
PIOS_Assert(valid);
uint32_t DataLength;
/* Read received data (63 bytes) */
/* Get the number of received data on the selected Endpoint */
DataLength = GetEPRxCount(usb_hid_dev->cfg->data_rx_ep);
if (DataLength > sizeof(usb_hid_dev->rx_packet_buffer)) {
DataLength = sizeof(usb_hid_dev->rx_packet_buffer);
}
/* Use the memory interface function to read from the selected endpoint */
PMAToUserBufferCopy((uint8_t *)usb_hid_dev->rx_packet_buffer,
GetEPRxAddr(usb_hid_dev->cfg->data_rx_ep),
DataLength);
if (!usb_hid_dev->rx_in_cb) {
/* No Rx call back registered, disable the receiver */
SetEPRxStatus(usb_hid_dev->cfg->data_rx_ep, EP_RX_NAK);
return;
}
/* The first byte is report ID (not checked), the second byte is the valid data length */
uint16_t headroom;
bool need_yield = false;
#ifdef PIOS_USB_BOARD_BL_HID_HAS_NO_LENGTH_BYTE
(usb_hid_dev->rx_in_cb)(usb_hid_dev->rx_in_context,
&usb_hid_dev->rx_packet_buffer[1],
sizeof(usb_hid_dev->rx_packet_buffer) - 1,
&headroom,
&need_yield);
#else
(usb_hid_dev->rx_in_cb)(usb_hid_dev->rx_in_context,
&usb_hid_dev->rx_packet_buffer[2],
usb_hid_dev->rx_packet_buffer[1],
&headroom,
&need_yield);
#endif
#ifdef PIOS_USB_BOARD_BL_HID_HAS_NO_LENGTH_BYTE
uint16_t max_payload_length = PIOS_USB_BOARD_HID_DATA_LENGTH - 1;
#else
uint16_t max_payload_length = PIOS_USB_BOARD_HID_DATA_LENGTH - 2;
#endif
if (headroom >= max_payload_length) {
/* We have room for a maximum length message */
SetEPRxStatus(usb_hid_dev->cfg->data_rx_ep, EP_RX_VALID);
} else {
/* Not enough room left for a message, apply backpressure */
SetEPRxStatus(usb_hid_dev->cfg->data_rx_ep, EP_RX_NAK);
}
#ifdef PIOS_INCLUDE_FREERTOS
if (need_yield) {
vPortYield();
}
#endif /* PIOS_INCLUDE_FREERTOS */
}
static uint32_t PIOS_USB_HID_Available(uint32_t usbhid_id)
{
return PIOS_USB_CheckAvailable(usbhid_id) ? COM_AVAILABLE_RXTX : COM_AVAILABLE_NONE;
}
#endif /* PIOS_INCLUDE_USB_HID */

View File

@ -0,0 +1,336 @@
/******************** (C) COPYRIGHT 2010 STMicroelectronics ********************
* File Name : usb_istr.c
* Author : MCD Application Team
* Version : V3.2.1
* Date : 07/05/2010
* Description : ISTR events interrupt service routines
********************************************************************************
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME.
* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*******************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include "pios.h"
#ifdef PIOS_INCLUDE_USB
#include "usb_lib.h"
#include "pios_usb_hid_pwr.h"
#include "pios_usb_hid_istr.h"
#include "pios_usb_hid.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
__IO uint16_t wIstr; /* ISTR register last read value */
__IO uint8_t bIntPackSOF = 0; /* SOFs received between 2 consecutive packets */
/* Extern variables ----------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/* function pointers to non-control endpoints service routines */
void(*pEpInt_IN[7]) (void) = {
EP1_IN_Callback, EP2_IN_Callback, EP3_IN_Callback, EP4_IN_Callback, EP5_IN_Callback, EP6_IN_Callback, EP7_IN_Callback,
};
void(*pEpInt_OUT[7]) (void) = {
EP1_OUT_Callback, EP2_OUT_Callback, EP3_OUT_Callback, EP4_OUT_Callback, EP5_OUT_Callback, EP6_OUT_Callback, EP7_OUT_Callback,
};
#ifndef STM32F10X_CL
/*******************************************************************************
* Function Name : USB_Istr
* Description : STR events interrupt service routine
* Input :
* Output :
* Return :
*******************************************************************************/
void USB_LP_CAN1_RX0_IRQHandler(void) // USB_Istr(void)
{
wIstr = _GetISTR();
#if (IMR_MSK & ISTR_CTR)
if (wIstr & ISTR_CTR & wInterrupt_Mask) {
/* servicing of the endpoint correct transfer interrupt */
/* clear of the CTR flag into the sub */
CTR_LP();
#ifdef CTR_CALLBACK
CTR_Callback();
#endif
}
#endif
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#if (IMR_MSK & ISTR_RESET)
if (wIstr & ISTR_RESET & wInterrupt_Mask) {
_SetISTR((uint16_t)CLR_RESET);
Device_Property.Reset();
#ifdef RESET_CALLBACK
RESET_Callback();
#endif
}
#endif
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#if (IMR_MSK & ISTR_DOVR)
if (wIstr & ISTR_DOVR & wInterrupt_Mask) {
_SetISTR((uint16_t)CLR_DOVR);
#ifdef DOVR_CALLBACK
DOVR_Callback();
#endif
}
#endif
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#if (IMR_MSK & ISTR_ERR)
if (wIstr & ISTR_ERR & wInterrupt_Mask) {
_SetISTR((uint16_t)CLR_ERR);
#ifdef ERR_CALLBACK
ERR_Callback();
#endif
}
#endif
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#if (IMR_MSK & ISTR_WKUP)
if (wIstr & ISTR_WKUP & wInterrupt_Mask) {
_SetISTR((uint16_t)CLR_WKUP);
Resume(RESUME_EXTERNAL);
#ifdef WKUP_CALLBACK
WKUP_Callback();
#endif
}
#endif
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#if (IMR_MSK & ISTR_SUSP)
if (wIstr & ISTR_SUSP & wInterrupt_Mask) {
/* check if SUSPEND is possible */
if (fSuspendEnabled) {
Suspend();
} else {
/* if not possible then resume after xx ms */
Resume(RESUME_LATER);
}
/* clear of the ISTR bit must be done after setting of CNTR_FSUSP */
_SetISTR((uint16_t)CLR_SUSP);
#ifdef SUSP_CALLBACK
SUSP_Callback();
#endif
}
#endif
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#if (IMR_MSK & ISTR_SOF)
if (wIstr & ISTR_SOF & wInterrupt_Mask) {
_SetISTR((uint16_t)CLR_SOF);
bIntPackSOF++;
#ifdef SOF_CALLBACK
SOF_Callback();
#endif
}
#endif
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#if (IMR_MSK & ISTR_ESOF)
if (wIstr & ISTR_ESOF & wInterrupt_Mask) {
_SetISTR((uint16_t)CLR_ESOF);
/* resume handling timing is made with ESOFs */
Resume(RESUME_ESOF); /* request without change of the machine state */
#ifdef ESOF_CALLBACK
ESOF_Callback();
#endif
}
#endif
} /* USB_Istr */
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#else /* STM32F10X_CL */
/*******************************************************************************
* Function Name : STM32_PCD_OTG_ISR_Handler
* Description : Handles all USB Device Interrupts
* Input : None
* Output : None
* Return : status
*******************************************************************************/
u32 STM32_PCD_OTG_ISR_Handler(void)
{
USB_OTG_GINTSTS_TypeDef gintr_status;
u32 retval = 0;
if (USBD_FS_IsDeviceMode()) { /* ensure that we are in device mode */
gintr_status.d32 = OTGD_FS_ReadCoreItr();
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
/* If there is no interrupt pending exit the interrupt routine */
if (!gintr_status.d32) {
return 0;
}
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
/* Early Suspend interrupt */
#ifdef INTR_ERLYSUSPEND
if (gintr_status.b.erlysuspend) {
retval |= OTGD_FS_Handle_EarlySuspend_ISR();
}
#endif /* INTR_ERLYSUSPEND */
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
/* End of Periodic Frame interrupt */
#ifdef INTR_EOPFRAME
if (gintr_status.b.eopframe) {
retval |= OTGD_FS_Handle_EOPF_ISR();
}
#endif /* INTR_EOPFRAME */
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
/* Non Periodic Tx FIFO Emty interrupt */
#ifdef INTR_NPTXFEMPTY
if (gintr_status.b.nptxfempty) {
retval |= OTGD_FS_Handle_NPTxFE_ISR();
}
#endif /* INTR_NPTXFEMPTY */
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
/* Wakeup or RemoteWakeup interrupt */
#ifdef INTR_WKUPINTR
if (gintr_status.b.wkupintr) {
retval |= OTGD_FS_Handle_Wakeup_ISR();
}
#endif /* INTR_WKUPINTR */
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
/* Suspend interrupt */
#ifdef INTR_USBSUSPEND
if (gintr_status.b.usbsuspend) {
/* check if SUSPEND is possible */
if (fSuspendEnabled) {
Suspend();
} else {
/* if not possible then resume after xx ms */
Resume(RESUME_LATER); /* This case shouldn't happen in OTG Device mode because
there's no ESOF interrupt to increment the ResumeS.bESOFcnt in the Resume state machine */
}
retval |= OTGD_FS_Handle_USBSuspend_ISR();
}
#endif /* INTR_USBSUSPEND */
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
/* Start of Frame interrupt */
#ifdef INTR_SOFINTR
if (gintr_status.b.sofintr) {
/* Update the frame number variable */
bIntPackSOF++;
retval |= OTGD_FS_Handle_Sof_ISR();
}
#endif /* INTR_SOFINTR */
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
/* Receive FIFO Queue Status Level interrupt */
#ifdef INTR_RXSTSQLVL
if (gintr_status.b.rxstsqlvl) {
retval |= OTGD_FS_Handle_RxStatusQueueLevel_ISR();
}
#endif /* INTR_RXSTSQLVL */
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
/* Enumeration Done interrupt */
#ifdef INTR_ENUMDONE
if (gintr_status.b.enumdone) {
retval |= OTGD_FS_Handle_EnumDone_ISR();
}
#endif /* INTR_ENUMDONE */
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
/* Reset interrutp */
#ifdef INTR_USBRESET
if (gintr_status.b.usbreset) {
retval |= OTGD_FS_Handle_UsbReset_ISR();
}
#endif /* INTR_USBRESET */
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
/* IN Endpoint interrupt */
#ifdef INTR_INEPINTR
if (gintr_status.b.inepint) {
retval |= OTGD_FS_Handle_InEP_ISR();
}
#endif /* INTR_INEPINTR */
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
/* OUT Endpoint interrupt */
#ifdef INTR_OUTEPINTR
if (gintr_status.b.outepintr) {
retval |= OTGD_FS_Handle_OutEP_ISR();
}
#endif /* INTR_OUTEPINTR */
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
/* Mode Mismatch interrupt */
#ifdef INTR_MODEMISMATCH
if (gintr_status.b.modemismatch) {
retval |= OTGD_FS_Handle_ModeMismatch_ISR();
}
#endif /* INTR_MODEMISMATCH */
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
/* Global IN Endpoints NAK Effective interrupt */
#ifdef INTR_GINNAKEFF
if (gintr_status.b.ginnakeff) {
retval |= OTGD_FS_Handle_GInNakEff_ISR();
}
#endif /* INTR_GINNAKEFF */
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
/* Global OUT Endpoints NAK effective interrupt */
#ifdef INTR_GOUTNAKEFF
if (gintr_status.b.goutnakeff) {
retval |= OTGD_FS_Handle_GOutNakEff_ISR();
}
#endif /* INTR_GOUTNAKEFF */
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
/* Isochrounous Out packet Dropped interrupt */
#ifdef INTR_ISOOUTDROP
if (gintr_status.b.isooutdrop) {
retval |= OTGD_FS_Handle_IsoOutDrop_ISR();
}
#endif /* INTR_ISOOUTDROP */
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
/* Endpoint Mismatch error interrupt */
#ifdef INTR_EPMISMATCH
if (gintr_status.b.epmismatch) {
retval |= OTGD_FS_Handle_EPMismatch_ISR();
}
#endif /* INTR_EPMISMATCH */
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
/* Incomplete Isochrous IN tranfer error interrupt */
#ifdef INTR_INCOMPLISOIN
if (gintr_status.b.incomplisoin) {
retval |= OTGD_FS_Handle_IncomplIsoIn_ISR();
}
#endif /* INTR_INCOMPLISOIN */
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
/* Incomplete Isochrous OUT tranfer error interrupt */
#ifdef INTR_INCOMPLISOOUT
if (gintr_status.b.outepintr) {
retval |= OTGD_FS_Handle_IncomplIsoOut_ISR();
}
#endif /* INTR_INCOMPLISOOUT */
}
return retval;
}
#endif /* STM32F10X_CL */
#endif /* PIOS_INCLUDE_USB */
/******************* (C) COPYRIGHT 2010 STMicroelectronics *****END OF FILE****/

View File

@ -0,0 +1,292 @@
/******************** (C) COPYRIGHT 2010 STMicroelectronics ********************
* File Name : usb_pwr.c
* Author : MCD Application Team
* Version : V3.2.1
* Date : 07/05/2010
* Description : Connection/disconnection & power management
********************************************************************************
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME.
* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*******************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include "pios.h"
#include "stm32f30x.h"
#include "usb_lib.h"
#include "usb_conf.h"
#include "pios_usb_hid_pwr.h"
#include "pios_usb_hid.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
__IO uint32_t bDeviceState = UNCONNECTED; /* USB device status */
__IO bool fSuspendEnabled = true; /* true when suspend is possible */
struct {
__IO RESUME_STATE eState;
__IO uint8_t bESOFcnt;
} ResumeS;
/* Extern variables ----------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Extern function prototypes ------------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/*******************************************************************************
* Function Name : USB_Cable_Config.
* Description : Software Connection/Disconnection of USB Cable.
* Input : NewState: new state.
* Output : None.
* Return : None
*******************************************************************************/
void USB_Cable_Config(FunctionalState __attribute__((unused)) NewState)
{}
/*******************************************************************************
* Function Name : PowerOn
* Description :
* Input : None.
* Output : None.
* Return : USB_SUCCESS.
*******************************************************************************/
RESULT PowerOn(void)
{
#ifndef STM32F10X_CL
uint16_t wRegVal;
/*** cable plugged-in ? ***/
USB_Cable_Config(ENABLE);
/*** CNTR_PWDN = 0 ***/
wRegVal = CNTR_FRES;
_SetCNTR(wRegVal);
/*** CNTR_FRES = 0 ***/
wInterrupt_Mask = 0;
_SetCNTR(wInterrupt_Mask);
/*** Clear pending interrupts ***/
_SetISTR(0);
/*** Set interrupt mask ***/
wInterrupt_Mask = CNTR_RESETM | CNTR_SUSPM | CNTR_WKUPM;
_SetCNTR(wInterrupt_Mask);
#endif /* STM32F10X_CL */
return USB_SUCCESS;
}
/*******************************************************************************
* Function Name : PowerOff
* Description : handles switch-off conditions
* Input : None.
* Output : None.
* Return : USB_SUCCESS.
*******************************************************************************/
RESULT PowerOff()
{
#ifndef STM32F10X_CL
/* disable all ints and force USB reset */
_SetCNTR(CNTR_FRES);
/* clear interrupt status register */
_SetISTR(0);
/* Disable the Pull-Up */
USB_Cable_Config(DISABLE);
/* switch-off device */
_SetCNTR(CNTR_FRES + CNTR_PDWN);
#endif /* STM32F10X_CL */
/* sw variables reset */
/* ... */
return USB_SUCCESS;
}
/*******************************************************************************
* Function Name : Enter_LowPowerMode.
* Description : Power-off system clocks and power while entering suspend mode.
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
void Enter_LowPowerMode(void)
{
/* Set the device state to suspend */
bDeviceState = SUSPENDED;
}
/*******************************************************************************
* Function Name : Suspend
* Description : sets suspend mode operating conditions
* Input : None.
* Output : None.
* Return : USB_SUCCESS.
*******************************************************************************/
void Suspend(void)
{
#ifndef STM32F10X_CL
uint16_t wCNTR;
/* suspend preparation */
/* ... */
/* macrocell enters suspend mode */
wCNTR = _GetCNTR();
wCNTR |= CNTR_FSUSP;
_SetCNTR(wCNTR);
#endif /* STM32F10X_CL */
/* ------------------ ONLY WITH BUS-POWERED DEVICES ---------------------- */
/* power reduction */
/* ... on connected devices */
#ifndef STM32F10X_CL
/* force low-power mode in the macrocell */
wCNTR = _GetCNTR();
wCNTR |= CNTR_LPMODE;
_SetCNTR(wCNTR);
#endif /* STM32F10X_CL */
/* switch-off the clocks */
/* ... */
Enter_LowPowerMode();
}
/*******************************************************************************
* Function Name : Leave_LowPowerMode.
* Description : Restores system clocks and power while exiting suspend mode.
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
void Leave_LowPowerMode(void)
{
DEVICE_INFO *pInfo = &Device_Info;
/* Set the device state to the correct state */
if (pInfo->Current_Configuration != 0) {
/* Device configured */
bDeviceState = CONFIGURED;
} else {
bDeviceState = ATTACHED;
}
}
/*******************************************************************************
* Function Name : Resume_Init
* Description : Handles wake-up restoring normal operations
* Input : None.
* Output : None.
* Return : USB_SUCCESS.
*******************************************************************************/
void Resume_Init(void)
{
#ifndef STM32F10X_CL
uint16_t wCNTR;
#endif /* STM32F10X_CL */
/* ------------------ ONLY WITH BUS-POWERED DEVICES ---------------------- */
/* restart the clocks */
/* ... */
#ifndef STM32F10X_CL
/* CNTR_LPMODE = 0 */
wCNTR = _GetCNTR();
wCNTR &= (~CNTR_LPMODE);
_SetCNTR(wCNTR);
#endif /* STM32F10X_CL */
/* restore full power */
/* ... on connected devices */
Leave_LowPowerMode();
#ifndef STM32F10X_CL
/* reset FSUSP bit */
_SetCNTR(IMR_MSK);
#endif /* STM32F10X_CL */
/* reverse suspend preparation */
/* ... */
}
/*******************************************************************************
* Function Name : Resume
* Description : This is the state machine handling resume operations and
* timing sequence. The control is based on the Resume structure
* variables and on the ESOF interrupt calling this subroutine
* without changing machine state.
* Input : a state machine value (RESUME_STATE)
* RESUME_ESOF doesn't change ResumeS.eState allowing
* decrementing of the ESOF counter in different states.
* Output : None.
* Return : None.
*******************************************************************************/
void Resume(RESUME_STATE eResumeSetVal)
{
#ifndef STM32F10X_CL
uint16_t wCNTR;
#endif /* STM32F10X_CL */
if (eResumeSetVal != RESUME_ESOF) {
ResumeS.eState = eResumeSetVal;
}
switch (ResumeS.eState) {
case RESUME_EXTERNAL:
Resume_Init();
ResumeS.eState = RESUME_OFF;
break;
case RESUME_INTERNAL:
Resume_Init();
ResumeS.eState = RESUME_START;
break;
case RESUME_LATER:
ResumeS.bESOFcnt = 2;
ResumeS.eState = RESUME_WAIT;
break;
case RESUME_WAIT:
ResumeS.bESOFcnt--;
if (ResumeS.bESOFcnt == 0) {
ResumeS.eState = RESUME_START;
}
break;
case RESUME_START:
#ifdef STM32F10X_CL
OTGD_FS_SetRemoteWakeup();
#else
wCNTR = _GetCNTR();
wCNTR |= CNTR_RESUME;
_SetCNTR(wCNTR);
#endif /* STM32F10X_CL */
ResumeS.eState = RESUME_ON;
ResumeS.bESOFcnt = 10;
break;
case RESUME_ON:
#ifndef STM32F10X_CL
ResumeS.bESOFcnt--;
if (ResumeS.bESOFcnt == 0) {
#endif /* STM32F10X_CL */
#ifdef STM32F10X_CL
OTGD_FS_ResetRemoteWakeup();
#else
wCNTR = _GetCNTR();
wCNTR &= (~CNTR_RESUME);
_SetCNTR(wCNTR);
#endif /* STM32F10X_CL */
ResumeS.eState = RESUME_OFF;
#ifndef STM32F10X_CL
}
#endif /* STM32F10X_CL */
break;
case RESUME_OFF:
case RESUME_ESOF:
default:
ResumeS.eState = RESUME_OFF;
break;
}
}
/******************* (C) COPYRIGHT 2010 STMicroelectronics *****END OF FILE****/

View File

@ -0,0 +1,572 @@
/**
******************************************************************************
* @addtogroup PIOS PIOS Core hardware abstraction layer
* @{
* @addtogroup PIOS_USBHOOK USB glue code
* @brief Glue between PiOS and STM32 libs
* @{
*
* @file pios_usbhook.c
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @brief Glue between PiOS and STM32 libs
* @see The GNU Public License (GPL) Version 3
*
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "pios.h"
#ifdef PIOS_INCLUDE_USB
#include "pios_usb.h" /* PIOS_USB_* */
#include "pios_usbhook.h"
#include "pios_usb_defs.h" /* struct usb_* */
#include "pios_usb_hid_pwr.h"
#include "pios_usb_cdc_priv.h" /* PIOS_USB_CDC_* */
#include "pios_usb_board_data.h" /* PIOS_USB_BOARD_* */
/* STM32 USB Library Definitions */
#include "usb_lib.h"
static void (*ep0_rxready_cb)(void) = 0;
static ONE_DESCRIPTOR Device_Descriptor;
void PIOS_USBHOOK_RegisterDevice(const uint8_t *desc, uint16_t desc_size)
{
Device_Descriptor.Descriptor = desc;
Device_Descriptor.Descriptor_Size = desc_size;
}
static ONE_DESCRIPTOR Config_Descriptor;
void PIOS_USBHOOK_RegisterConfig(__attribute__((unused)) uint8_t config_id, const uint8_t *desc, uint16_t desc_size)
{
Config_Descriptor.Descriptor = desc;
Config_Descriptor.Descriptor_Size = desc_size;
}
static ONE_DESCRIPTOR String_Descriptor[4];
void PIOS_USBHOOK_RegisterString(enum usb_string_desc string_id, const uint8_t *desc, uint16_t desc_size)
{
if (string_id < NELEMENTS(String_Descriptor)) {
String_Descriptor[string_id].Descriptor = desc;
String_Descriptor[string_id].Descriptor_Size = desc_size;
}
}
static ONE_DESCRIPTOR Hid_Descriptor;
void PIOS_USB_HID_RegisterHidDescriptor(const uint8_t *desc, uint16_t desc_size)
{
Hid_Descriptor.Descriptor = desc;
Hid_Descriptor.Descriptor_Size = desc_size;
}
static ONE_DESCRIPTOR Hid_Report_Descriptor;
void PIOS_USB_HID_RegisterHidReport(const uint8_t *desc, uint16_t desc_size)
{
Hid_Report_Descriptor.Descriptor = desc;
Hid_Report_Descriptor.Descriptor_Size = desc_size;
}
void PIOS_USBHOOK_Deactivate(void)
{}
#include "stm32f30x.h" /* __IO */
__IO uint8_t EXTI_Enable;
uint32_t ProtocolValue;
DEVICE Device_Table = {
PIOS_USB_BOARD_EP_NUM,
1
};
static void PIOS_USBHOOK_Init(void);
static void PIOS_USBHOOK_Reset(void);
static void PIOS_USBHOOK_Status_In(void);
static void PIOS_USBHOOK_Status_Out(void);
static RESULT PIOS_USBHOOK_Data_Setup(uint8_t RequestNo);
static RESULT PIOS_USBHOOK_NoData_Setup(uint8_t RequestNo);
static RESULT PIOS_USBHOOK_Get_Interface_Setting(uint8_t Interface, uint8_t AlternateSetting);
static const uint8_t *PIOS_USBHOOK_GetDeviceDescriptor(uint16_t Length);
static const uint8_t *PIOS_USBHOOK_GetConfigDescriptor(uint16_t Length);
static const uint8_t *PIOS_USBHOOK_GetStringDescriptor(uint16_t Length);
DEVICE_PROP Device_Property = {
.Init = PIOS_USBHOOK_Init,
.Reset = PIOS_USBHOOK_Reset,
.Process_Status_IN = PIOS_USBHOOK_Status_In,
.Process_Status_OUT = PIOS_USBHOOK_Status_Out,
.Class_Data_Setup = PIOS_USBHOOK_Data_Setup,
.Class_NoData_Setup = PIOS_USBHOOK_NoData_Setup,
.Class_Get_Interface_Setting = PIOS_USBHOOK_Get_Interface_Setting,
.GetDeviceDescriptor = PIOS_USBHOOK_GetDeviceDescriptor,
.GetConfigDescriptor = PIOS_USBHOOK_GetConfigDescriptor,
.GetStringDescriptor = PIOS_USBHOOK_GetStringDescriptor,
.RxEP_buffer = 0,
.MaxPacketSize = 0x40,
};
static void PIOS_USBHOOK_SetConfiguration(void);
static void PIOS_USBHOOK_SetDeviceAddress(void);
USER_STANDARD_REQUESTS User_Standard_Requests = {
.User_GetConfiguration = NOP_Process,
.User_SetConfiguration = PIOS_USBHOOK_SetConfiguration,
.User_GetInterface = NOP_Process,
.User_SetInterface = NOP_Process,
.User_GetStatus = NOP_Process,
.User_ClearFeature = NOP_Process,
.User_SetEndPointFeature = NOP_Process,
.User_SetDeviceFeature = NOP_Process,
.User_SetDeviceAddress = PIOS_USBHOOK_SetDeviceAddress
};
static RESULT PIOS_USBHOOK_SetProtocol(void);
static const uint8_t *PIOS_USBHOOK_GetProtocolValue(uint16_t Length);
static const uint8_t *PIOS_USBHOOK_GetReportDescriptor(uint16_t Length);
static const uint8_t *PIOS_USBHOOK_GetHIDDescriptor(uint16_t Length);
/*******************************************************************************
* Function Name : PIOS_USBHOOK_Init.
* Description : Custom HID init routine.
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
static void PIOS_USBHOOK_Init(void)
{
pInformation->Current_Configuration = 0;
/* Connect the device */
PowerOn();
/* Perform basic device initialization operations */
USB_SIL_Init();
bDeviceState = UNCONNECTED;
}
/*******************************************************************************
* Function Name : PIOS_USBHOOK_Reset.
* Description : Custom HID reset routine.
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
static void PIOS_USBHOOK_Reset(void)
{
/* Set DEVICE as not configured */
pInformation->Current_Configuration = 0;
pInformation->Current_Interface = 0; /*the default Interface */
/* Current Feature initialization */
pInformation->Current_Feature = 0;
#ifdef STM32F10X_CL
/* EP0 is already configured in DFU_Init() by USB_SIL_Init() function */
/* Init EP1 IN as Interrupt endpoint */
OTG_DEV_EP_Init(EP1_IN, OTG_DEV_EP_TYPE_INT, 2);
/* Init EP1 OUT as Interrupt endpoint */
OTG_DEV_EP_Init(EP1_OUT, OTG_DEV_EP_TYPE_INT, 2);
#else
SetBTABLE(BTABLE_ADDRESS);
/* Initialize Endpoint 0 (Control) */
SetEPType(ENDP0, EP_CONTROL);
SetEPTxAddr(ENDP0, ENDP0_TXADDR);
SetEPTxStatus(ENDP0, EP_TX_STALL);
Clear_Status_Out(ENDP0);
SetEPRxAddr(ENDP0, ENDP0_RXADDR);
SetEPRxCount(ENDP0, Device_Property.MaxPacketSize);
SetEPRxValid(ENDP0);
#if defined(PIOS_INCLUDE_USB_HID)
/* Initialize Endpoint 1 (HID) */
SetEPType(ENDP1, EP_INTERRUPT);
SetEPTxAddr(ENDP1, ENDP1_TXADDR);
SetEPTxCount(ENDP1, PIOS_USB_BOARD_HID_DATA_LENGTH);
SetEPTxStatus(ENDP1, EP_TX_NAK);
SetEPRxAddr(ENDP1, ENDP1_RXADDR);
SetEPRxCount(ENDP1, PIOS_USB_BOARD_HID_DATA_LENGTH);
SetEPRxStatus(ENDP1, EP_RX_VALID);
#endif /* PIOS_INCLUDE_USB_HID */
#if defined(PIOS_INCLUDE_USB_CDC)
/* Initialize Endpoint 2 (CDC Call Control) */
SetEPType(ENDP2, EP_INTERRUPT);
SetEPTxAddr(ENDP2, ENDP2_TXADDR);
SetEPTxStatus(ENDP2, EP_TX_NAK);
SetEPRxAddr(ENDP2, ENDP2_RXADDR);
SetEPRxCount(ENDP2, PIOS_USB_BOARD_CDC_MGMT_LENGTH);
SetEPRxStatus(ENDP2, EP_RX_DIS);
/* Initialize Endpoint 3 (CDC Data) */
SetEPType(ENDP3, EP_BULK);
SetEPTxAddr(ENDP3, ENDP3_TXADDR);
SetEPTxStatus(ENDP3, EP_TX_NAK);
SetEPRxAddr(ENDP3, ENDP3_RXADDR);
SetEPRxCount(ENDP3, PIOS_USB_BOARD_CDC_DATA_LENGTH);
SetEPRxStatus(ENDP3, EP_RX_VALID);
#endif /* PIOS_INCLUDE_USB_CDC */
/* Set this device to response on default address */
SetDeviceAddress(0);
#endif /* STM32F10X_CL */
bDeviceState = ATTACHED;
}
/*******************************************************************************
* Function Name : PIOS_USBHOOK_SetConfiguration.
* Description : Update the device state to configured
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
static void PIOS_USBHOOK_SetConfiguration(void)
{
if (pInformation->Current_Configuration != 0) {
/* Device configured */
bDeviceState = CONFIGURED;
}
/* Enable transfers */
PIOS_USB_ChangeConnectionState(pInformation->Current_Configuration != 0);
}
/*******************************************************************************
* Function Name : PIOS_USBHOOK_SetConfiguration.
* Description : Update the device state to addressed.
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
static void PIOS_USBHOOK_SetDeviceAddress(void)
{
bDeviceState = ADDRESSED;
}
/*******************************************************************************
* Function Name : PIOS_USBHOOK_Status_In.
* Description : status IN routine.
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
static void PIOS_USBHOOK_Status_In(void)
{
/* this callback gets executed after sending ZLP and doing In0_Process(), to ack */
if (ep0_rxready_cb) {
ep0_rxready_cb();
ep0_rxready_cb = 0;
}
}
/*******************************************************************************
* Function Name : PIOS_USBHOOK_Status_Out
* Description : status OUT routine.
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
static void PIOS_USBHOOK_Status_Out(void)
{}
/*******************************************************************************
* Function Name : PIOS_USBHOOK_Data_Setup
* Description : Handle the data class specific requests.
* Input : Request Nb.
* Output : None.
* Return : USB_UNSUPPORT or USB_SUCCESS.
*******************************************************************************/
extern uint8_t *PIOS_USB_CDC_SetLineCoding(uint16_t Length);
extern const uint8_t *PIOS_USB_CDC_GetLineCoding(uint16_t Length);
extern void PIOS_USB_CDC_SetLineCoding_Completed();
static RESULT PIOS_USBHOOK_Data_Setup(uint8_t RequestNo)
{
uint8_t *(*CopyOutRoutine)(uint16_t);
const uint8_t *(*CopyInRoutine)(uint16_t);
CopyInRoutine = NULL;
CopyOutRoutine = NULL;
switch (Type_Recipient) {
case (STANDARD_REQUEST | INTERFACE_RECIPIENT):
switch (pInformation->USBwIndex0) {
#if defined(PIOS_INCLUDE_USB_CDC)
case 2: /* HID Interface */
#else
case 0: /* HID Interface */
#endif
switch (RequestNo) {
case GET_DESCRIPTOR:
switch (pInformation->USBwValue1) {
case USB_DESC_TYPE_REPORT:
CopyInRoutine = PIOS_USBHOOK_GetReportDescriptor;
break;
case USB_DESC_TYPE_HID:
CopyInRoutine = PIOS_USBHOOK_GetHIDDescriptor;
break;
}
}
}
break;
case (CLASS_REQUEST | INTERFACE_RECIPIENT):
switch (pInformation->USBwIndex0) {
#if defined(PIOS_INCLUDE_USB_CDC)
case 2: /* HID Interface */
#else
case 0: /* HID Interface */
#endif
switch (RequestNo) {
case USB_HID_REQ_GET_PROTOCOL:
CopyInRoutine = PIOS_USBHOOK_GetProtocolValue;
break;
}
break;
#if defined(PIOS_INCLUDE_USB_CDC)
case 0: /* CDC Call Control Interface */
switch (RequestNo) {
case USB_CDC_REQ_SET_LINE_CODING:
CopyOutRoutine = PIOS_USB_CDC_SetLineCoding;
ep0_rxready_cb = PIOS_USB_CDC_SetLineCoding_Completed;
break;
case USB_CDC_REQ_GET_LINE_CODING:
CopyInRoutine = PIOS_USB_CDC_GetLineCoding;
break;
}
break;
case 1: /* CDC Data Interface */
switch (RequestNo) {
case 0:
break;
}
break;
#endif /* PIOS_INCLUDE_USB_CDC */
}
break;
}
/* No registered copy routine */
if ((CopyInRoutine == NULL) && (CopyOutRoutine == NULL)) {
return USB_UNSUPPORT;
}
/* Registered copy in AND copy out routine */
if ((CopyInRoutine != NULL) && (CopyOutRoutine != NULL)) {
/* This should never happen */
return USB_UNSUPPORT;
}
if (CopyInRoutine != NULL) {
pInformation->Ctrl_Info.CopyData = (typeof(pInformation->Ctrl_Info.CopyData))CopyInRoutine;
pInformation->Ctrl_Info.Usb_wOffset = 0;
(*CopyInRoutine)(0);
} else if (CopyOutRoutine != NULL) {
pInformation->Ctrl_Info.CopyData = CopyOutRoutine;
pInformation->Ctrl_Info.Usb_rOffset = 0;
(*CopyOutRoutine)(0);
}
return USB_SUCCESS;
}
/*******************************************************************************
* Function Name : PIOS_USBHOOK_NoData_Setup
* Description : handle the no data class specific requests
* Input : Request Nb.
* Output : None.
* Return : USB_UNSUPPORT or USB_SUCCESS.
*******************************************************************************/
extern RESULT PIOS_USB_CDC_SetControlLineState(void);
static RESULT PIOS_USBHOOK_NoData_Setup(uint8_t RequestNo)
{
switch (Type_Recipient) {
case (CLASS_REQUEST | INTERFACE_RECIPIENT):
switch (pInformation->USBwIndex0) {
#if defined(PIOS_INCLUDE_USB_CDC)
case 2: /* HID */
#else
case 0: /* HID */
#endif
switch (RequestNo) {
case USB_HID_REQ_SET_PROTOCOL:
return PIOS_USBHOOK_SetProtocol();
break;
}
break;
#if defined(PIOS_INCLUDE_USB_CDC)
case 0: /* CDC Call Control Interface */
switch (RequestNo) {
case USB_CDC_REQ_SET_CONTROL_LINE_STATE:
return PIOS_USB_CDC_SetControlLineState();
break;
}
break;
#endif /* PIOS_INCLUDE_USB_CDC */
}
break;
}
return USB_UNSUPPORT;
}
/*******************************************************************************
* Function Name : PIOS_USBHOOK_GetDeviceDescriptor.
* Description : Gets the device descriptor.
* Input : Length
* Output : None.
* Return : The address of the device descriptor.
*******************************************************************************/
static const uint8_t *PIOS_USBHOOK_GetDeviceDescriptor(uint16_t Length)
{
return Standard_GetDescriptorData(Length, &Device_Descriptor);
}
/*******************************************************************************
* Function Name : PIOS_USBHOOK_GetConfigDescriptor.
* Description : Gets the configuration descriptor.
* Input : Length
* Output : None.
* Return : The address of the configuration descriptor.
*******************************************************************************/
static const uint8_t *PIOS_USBHOOK_GetConfigDescriptor(uint16_t Length)
{
return Standard_GetDescriptorData(Length, &Config_Descriptor);
}
/*******************************************************************************
* Function Name : PIOS_USBHOOK_GetStringDescriptor
* Description : Gets the string descriptors according to the needed index
* Input : Length
* Output : None.
* Return : The address of the string descriptors.
*******************************************************************************/
static const uint8_t *PIOS_USBHOOK_GetStringDescriptor(uint16_t Length)
{
uint8_t wValue0 = pInformation->USBwValue0;
if (wValue0 > 4) {
return NULL;
} else {
return Standard_GetDescriptorData(Length, &String_Descriptor[wValue0]);
}
}
/*******************************************************************************
* Function Name : PIOS_USBHOOK_GetReportDescriptor.
* Description : Gets the HID report descriptor.
* Input : Length
* Output : None.
* Return : The address of the configuration descriptor.
*******************************************************************************/
static const uint8_t *PIOS_USBHOOK_GetReportDescriptor(uint16_t Length)
{
return Standard_GetDescriptorData(Length, &Hid_Report_Descriptor);
}
/*******************************************************************************
* Function Name : PIOS_USBHOOK_GetHIDDescriptor.
* Description : Gets the HID descriptor.
* Input : Length
* Output : None.
* Return : The address of the configuration descriptor.
*******************************************************************************/
static const uint8_t *PIOS_USBHOOK_GetHIDDescriptor(uint16_t Length)
{
return Standard_GetDescriptorData(Length, &Hid_Descriptor);
}
/*******************************************************************************
* Function Name : PIOS_USBHOOK_Get_Interface_Setting.
* Description : tests the interface and the alternate setting according to the
* supported one.
* Input : - Interface : interface number.
* - AlternateSetting : Alternate Setting number.
* Output : None.
* Return : USB_SUCCESS or USB_UNSUPPORT.
*******************************************************************************/
static RESULT PIOS_USBHOOK_Get_Interface_Setting(uint8_t Interface, uint8_t AlternateSetting)
{
if (AlternateSetting > 0) {
return USB_UNSUPPORT;
} else if (Interface > 0) {
return USB_UNSUPPORT;
}
return USB_SUCCESS;
}
/*******************************************************************************
* Function Name : PIOS_USBHOOK_SetProtocol
* Description : Set Protocol request routine.
* Input : None.
* Output : None.
* Return : USB SUCCESS.
*******************************************************************************/
static RESULT PIOS_USBHOOK_SetProtocol(void)
{
uint8_t wValue0 = pInformation->USBwValue0;
ProtocolValue = wValue0;
return USB_SUCCESS;
}
/*******************************************************************************
* Function Name : PIOS_USBHOOK_GetProtocolValue
* Description : get the protocol value
* Input : Length.
* Output : None.
* Return : address of the protcol value.
*******************************************************************************/
static const uint8_t *PIOS_USBHOOK_GetProtocolValue(uint16_t Length)
{
if (Length == 0) {
pInformation->Ctrl_Info.Usb_wLength = 1;
return NULL;
} else {
return (uint8_t *)(&ProtocolValue);
}
}
#endif /* PIOS_INCLUDE_USB */
/******************* (C) COPYRIGHT 2010 STMicroelectronics *****END OF FILE****/

View File

@ -0,0 +1,186 @@
/**
******************************************************************************
* @addtogroup PIOS PIOS Core hardware abstraction layer
* @{
* @addtogroup PIOS_WDG Watchdog Functions
* @brief PIOS Comamnds to initialize and clear watchdog timer
* @{
*
* @file pios_wdg.c
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
* Parts by Thorsten Klose (tk@midibox.org) (tk@midibox.org)
* @brief Hardware Abstraction Layer for SPI ports of STM32
* @see The GNU Public License (GPL) Version 3
* @notes
*
* The PIOS Watchdog provides a HAL to initialize a watchdog
*
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* @todo This is virtually identical to the F1xx code and should be merged.
*/
#include "pios.h"
#ifdef PIOS_INCLUDE_WDG
#include "stm32f30x_iwdg.h"
#include "stm32f30x_dbgmcu.h"
#include "stm32f30x_rtc.h"
static struct wdg_configuration {
uint16_t used_flags;
uint16_t bootup_flags;
} wdg_configuration;
/**
* @brief Initialize the watchdog timer for a specified timeout
*
* It is important to note that this function returns the achieved timeout
* for this hardware. For hardware independence this should be checked when
* scheduling updates. Other hardware dependent details may need to be
* considered such as a window time which sets a minimum update time,
* and this function should return a recommended delay for clearing.
*
* For the STM32 nominal clock rate is 32 khz, but for the maximum clock rate of
* 60 khz and a prescaler of 4 yields a clock rate of 15 khz. The delay that is
* set in the watchdog assumes the nominal clock rate, but the delay for FreeRTOS
* to use is 75% of the minimal delay.
*
* @returns Maximum recommended delay between updates based on PIOS_WATCHDOG_TIMEOUT constant
*/
uint16_t PIOS_WDG_Init()
{
uint16_t delay = ((uint32_t)PIOS_WATCHDOG_TIMEOUT * 60) / 16;
if (delay > 0x0fff) {
delay = 0x0fff;
}
#if defined(PIOS_INCLUDE_WDG)
DBGMCU_APB1PeriphConfig(DBGMCU_IWDG_STOP, ENABLE); // OP-1272 : write in APB1 register
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
IWDG_SetPrescaler(IWDG_Prescaler_16);
IWDG_SetReload(delay);
IWDG_ReloadCounter();
IWDG_Enable();
// watchdog flags now stored in backup registers
PWR_BackupAccessCmd(ENABLE);
wdg_configuration.bootup_flags = RTC_ReadBackupRegister(PIOS_WDG_REGISTER);
#endif
return delay;
}
/**
* @brief Register a module against the watchdog
*
* There are two ways to use PIOS WDG: this is for when
* multiple modules must be monitored. In this case they
* must first register against the watchdog system and
* only when all of the modules have been updated with the
* watchdog be cleared. Each module must have its own
* bit in the 16 bit
*
* @param[in] flag the bit this module wants to use
* @returns True if that bit is unregistered
*/
bool PIOS_WDG_RegisterFlag(uint16_t flag_requested)
{
// flag are being registered so we are in module initialization phase
// clear the WDG to prevent timeout while initializing modules. (OP-815)
PIOS_WDG_Clear();
/* Fail if flag already registered */
if (wdg_configuration.used_flags & flag_requested) {
return false;
}
// FIXME: Protect with semaphore
wdg_configuration.used_flags |= flag_requested;
return true;
}
/**
* @brief Function called by modules to indicate they are still running
*
* This function will set this flag in the active flags register (which is
* a backup regsiter) and if all the registered flags are set will clear
* the watchdog and set only this flag in the backup register
*
* @param[in] flag the flag to set
* @return true if the watchdog cleared, false if flags are pending
*/
bool PIOS_WDG_UpdateFlag(uint16_t flag)
{
// we can probably avoid using a semaphore here which will be good for
// efficiency and not blocking critical tasks. race condition could
// overwrite their flag update, but unlikely to block _all_ of them
// for the timeout window
uint16_t cur_flags = RTC_ReadBackupRegister(PIOS_WDG_REGISTER);
if ((cur_flags | flag) == wdg_configuration.used_flags) {
PIOS_WDG_Clear();
RTC_WriteBackupRegister(PIOS_WDG_REGISTER, flag);
return true;
} else {
RTC_WriteBackupRegister(PIOS_WDG_REGISTER, cur_flags | flag);
return false;
}
}
/**
* @brief Returns the flags that were set at bootup
*
* This is used for diagnostics, if only one flag not set this
* was likely the module that wasn't running before reset
*
* @return The active flags register from bootup
*/
uint16_t PIOS_WDG_GetBootupFlags()
{
return wdg_configuration.bootup_flags;
}
/**
* @brief Returns the currently active flags
*
* For external monitoring
*
* @return The active flags register
*/
uint16_t PIOS_WDG_GetActiveFlags()
{
return RTC_ReadBackupRegister(PIOS_WDG_REGISTER);
}
/**
* @brief Clear the watchdog timer
*
* This function must be called at the appropriate delay to prevent a reset event occuring
*/
void PIOS_WDG_Clear(void)
{
#if defined(PIOS_INCLUDE_WDG)
IWDG_ReloadCounter();
#endif
}
#endif /* PIOS_INCLUDE_WDG */

View File

@ -0,0 +1,208 @@
/**
******************************************************************************
*
* @file pios_ws2811.c
* @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017.
* @brief A driver for ws2811 rgb led controller.
* this is a port of the CleanFlight/BetaFlight implementation.
* @see The GNU Public License (GPL) Version 3
*
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "pios.h"
#include "pios_ws2811.h"
#include "pios_ws2811_cfg.h"
#define WS2811_BITS_PER_LED 24
// for 50us delay
#define WS2811_DELAY_BUFFER_LENGTH 42
#define WS2811_DATA_BUFFER_SIZE (WS2811_BITS_PER_LED * PIOS_WS2811_NUMLEDS)
// number of bytes needed is #LEDs * 24 bytes + 42 trailing bytes)
#define WS2811_DMA_BUFFER_SIZE (WS2811_DATA_BUFFER_SIZE + WS2811_DELAY_BUFFER_LENGTH)
#define WS2811_TIMER_HZ 24000000
#define WS2811_TIMER_PERIOD 29
// timer compare value for logical 1
#define BIT_COMPARE_1 17
// timer compare value for logical 0
#define BIT_COMPARE_0 9
#define PIOS_WS2811_MAGIC 0x00281100
struct pios_ws2811_dev {
uint32_t magic;
const struct pios_ws2811_cfg *config;
uint8_t dma_buffer[WS2811_DMA_BUFFER_SIZE];
bool dma_active;
};
struct pios_ws2811_dev *ws2811_dev;
void PIOS_WS2811_Init(uint32_t *dev_id, const struct pios_ws2811_cfg *ws2811_cfg)
{
if (ws2811_dev) {
return;
}
ws2811_dev = (struct pios_ws2811_dev *)pios_malloc(sizeof(*ws2811_dev));
PIOS_Assert(ws2811_dev);
memset(ws2811_dev, 0, sizeof(*ws2811_dev));
ws2811_dev->magic = PIOS_WS2811_MAGIC;
ws2811_dev->config = ws2811_cfg;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
DMA_InitTypeDef DMA_InitStructure;
GPIO_Init(ws2811_cfg->pin.gpio, (GPIO_InitTypeDef *)&ws2811_cfg->pin.init);
GPIO_PinAFConfig(ws2811_cfg->pin.gpio, ws2811_cfg->pin.pin_source, ws2811_cfg->remap);
/* Compute the prescaler value */
uint16_t prescalerValue = (uint16_t)(SystemCoreClock / WS2811_TIMER_HZ) - 1;
/* Time base configuration */
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Period = WS2811_TIMER_PERIOD; // 800kHz
TIM_TimeBaseStructure.TIM_Prescaler = prescalerValue;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(ws2811_cfg->timer, &TIM_TimeBaseStructure);
/* PWM1 Mode configuration: Channel1 */
TIM_OCStructInit(&TIM_OCInitStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 0;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
switch (ws2811_cfg->timer_chan) {
case TIM_Channel_1:
TIM_OC1Init(ws2811_cfg->timer, &TIM_OCInitStructure);
TIM_OC1PreloadConfig(ws2811_cfg->timer, TIM_OCPreload_Enable);
break;
case TIM_Channel_2:
TIM_OC2Init(ws2811_cfg->timer, &TIM_OCInitStructure);
TIM_OC2PreloadConfig(ws2811_cfg->timer, TIM_OCPreload_Enable);
break;
case TIM_Channel_3:
TIM_OC3Init(ws2811_cfg->timer, &TIM_OCInitStructure);
TIM_OC3PreloadConfig(ws2811_cfg->timer, TIM_OCPreload_Enable);
break;
case TIM_Channel_4:
TIM_OC4Init(ws2811_cfg->timer, &TIM_OCInitStructure);
TIM_OC4PreloadConfig(ws2811_cfg->timer, TIM_OCPreload_Enable);
break;
}
TIM_CtrlPWMOutputs(ws2811_cfg->timer, ENABLE);
/* configure DMA */
// NVIC setup here
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = ws2811_cfg->dma_irqn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_LOW;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
DMA_DeInit(ws2811_cfg->dma_chan);
DMA_StructInit(&DMA_InitStructure);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ws2811_cfg->timer->CCR1 + ws2811_cfg->timer_chan;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ws2811_dev->dma_buffer;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_BufferSize = WS2811_DMA_BUFFER_SIZE;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(ws2811_cfg->dma_chan, &DMA_InitStructure);
TIM_DMACmd(ws2811_cfg->timer, ws2811_cfg->timer_dma_source, ENABLE);
DMA_ITConfig(ws2811_cfg->dma_chan, DMA_IT_TC, ENABLE);
*dev_id = (uint32_t)ws2811_dev;
}
void PIOS_WS2811_DMA_irq_handler()
{
if (!ws2811_dev) {
return;
}
if (DMA_GetITStatus(ws2811_dev->config->dma_tcif)) {
ws2811_dev->dma_active = false;
DMA_Cmd(ws2811_dev->config->dma_chan, DISABLE);
DMA_ClearITPendingBit(ws2811_dev->config->dma_tcif);
}
}
/**
* Set a led color
* @param c color
* @param led led number
* @param update Perform an update after changing led color
*/
void PIOS_WS2811_setColorRGB(Color_t c, uint8_t led, bool update)
{
if (!ws2811_dev || (led >= PIOS_WS2811_NUMLEDS)) {
return;
}
int offset = led * WS2811_BITS_PER_LED;
uint32_t grb = (c.G << 16) | (c.R << 8) | (c.B);
for (int bit = (WS2811_BITS_PER_LED - 1); bit >= 0; --bit) {
ws2811_dev->dma_buffer[offset++] = (grb & (1 << bit)) ? BIT_COMPARE_1 : BIT_COMPARE_0;
}
if (update) {
PIOS_WS2811_Update();
}
}
void PIOS_WS2811_Update()
{
if (!ws2811_dev || ws2811_dev->dma_active) {
return;
}
ws2811_dev->dma_active = true;
DMA_SetCurrDataCounter(ws2811_dev->config->dma_chan, WS2811_DMA_BUFFER_SIZE); // load number of bytes to be transferred
TIM_SetCounter(ws2811_dev->config->timer, 0);
TIM_Cmd(ws2811_dev->config->timer, ENABLE);
DMA_Cmd(ws2811_dev->config->dma_chan, ENABLE);
}

View File

@ -0,0 +1,189 @@
/**
******************************************************************************
* @addtogroup PIOS PIOS Core hardware abstraction layer
* @{
*
* @file startup.c
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
* @author Tau Labs, http://taulabs.org, Copyright (C) 2012-2013
* @brief C based startup of F3
* @see The GNU Public License (GPL) Version 3
*
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <string.h>
#include <stm32f30x.h>
/* prototype for main() that tells us not to worry about it possibly returning */
extern int main(void) __attribute__((noreturn));
/* prototype our _main() to avoid prolog/epilog insertion and other related junk */
void _main(void) __attribute__((noreturn, naked, no_instrument_function));
/** default handler for CPU exceptions */
static void default_cpu_handler(void) __attribute__((noreturn, naked, no_instrument_function));
/** BSS symbols XXX should have a header that defines all of these */
extern char _sbss, _ebss;
/** DATA symbols XXX should have a header that defines all of these */
extern char _sidata, _sdata, _edata, _sfast, _efast;
/** The bootstrap/IRQ stack XXX should define size somewhere else */
char irq_stack[1024] __attribute__((section(".irqstack")));
/** exception handler */
typedef void (vector)(void);
/** CortexM3 CPU vectors */
struct cm3_vectors {
void *initial_stack;
vector *entry;
vector *vectors[14];
};
/**
* Initial startup code.
*/
void _main(void)
{
// load the stack base for the current stack before we attempt to branch to any function
// that might bounds-check the stack
asm volatile ("mov r10, %0" : : "r" (&irq_stack[0]) :);
/* enable usage, bus and memory faults */
SCB->SHCSR |= SCB_SHCSR_USGFAULTENA_Msk | SCB_SHCSR_BUSFAULTENA_Msk | SCB_SHCSR_MEMFAULTENA_Msk;
/* configure FP state save behaviour - automatic, lazy save */
FPU->FPCCR |= FPU_FPCCR_ASPEN_Msk | FPU_FPCCR_LSPEN_Msk;
/* configure default FPU state */
FPU->FPDSCR |= FPU_FPDSCR_DN_Msk; /* enable Default NaN */
FPU->FPDSCR |= FPU_FPDSCR_FZ_Msk; /* Use flush to zero for very
* small values. */
/* enable the FPU */
SCB->CPACR |= (0xf << 20); // turn on CP10/11 for FP support on cores that implement it
/* copy initialised data from flash to RAM */
memcpy(&_sdata, &_sidata, &_edata - &_sdata);
/* zero the BSS */
memset(&_sbss, 0, &_ebss - &_sbss);
/* zero any 'fast' RAM that's been used */
memset(&_sfast, 0, &_efast - &_sfast);
/* fill most of the IRQ/bootstrap stack with a watermark pattern so we can measure how much is used */
/* leave a little space at the top in case memset() isn't a leaf with no locals */
memset(&irq_stack, 0xa5, sizeof(irq_stack) - 64);
/* call main */
(void)main();
}
/**
* Default handler for CPU exceptions.
*/
static void default_cpu_handler(void)
{
for (;;) {
;
}
}
static void default_NMI_Handler()
{
default_cpu_handler();
}
static void default_HardFault_Handler()
{
default_cpu_handler();
}
static void default_MemManage_Handler()
{
default_cpu_handler();
}
static void default_BusFault_Handler()
{
default_cpu_handler();
}
static void default_UsageFault_Handler()
{
default_cpu_handler();
}
static void default_DebugMon_Handler()
{
default_cpu_handler();
}
static void default_vPortSVCHandler()
{
default_cpu_handler();
}
static void default_xPortPendSVHandler()
{
default_cpu_handler();
}
static void default_xPortSysTickHandler()
{
default_cpu_handler();
}
/** Prototype for optional exception vector handlers */
#define HANDLER(_name) extern vector _name __attribute__((weak, alias("default_" #_name)))
/* standard CMSIS vector names */
HANDLER(NMI_Handler);
HANDLER(HardFault_Handler);
HANDLER(MemManage_Handler);
HANDLER(BusFault_Handler);
HANDLER(UsageFault_Handler);
HANDLER(DebugMon_Handler);
/* these vectors point directly to the relevant FreeRTOS functions if they are defined */
HANDLER(vPortSVCHandler);
HANDLER(xPortPendSVHandler);
HANDLER(xPortSysTickHandler);
/** CortexM3 vector table */
struct cm3_vectors cpu_vectors __attribute((section(".cpu_vectors"))) =
{
.initial_stack = &irq_stack[sizeof(irq_stack)],
.entry = (vector *)_main,
.vectors = {
NMI_Handler,
HardFault_Handler,
MemManage_Handler,
BusFault_Handler,
UsageFault_Handler,
0,
0,
0,
0,
vPortSVCHandler,
DebugMon_Handler, // Maybe
0,
xPortPendSVHandler,
xPortSysTickHandler,
}
};
/**
* @}
*/

View File

@ -0,0 +1,370 @@
/**
******************************************************************************
* @file system_stm32f30x.c
* @author MCD Application Team
* @version V1.0.0
* @date 04-September-2012
* @brief CMSIS Cortex-M4 Device Peripheral Access Layer System Source File.
* This file contains the system clock configuration for STM32F30x devices,
* and is generated by the clock configuration tool
* stm32f30x_Clock_Configuration_V1.0.0.xls
*
* 1. This file provides two functions and one global variable to be called from
* user application:
* - SystemInit(): Setups the system clock (System clock source, PLL Multiplier
* and Divider factors, AHB/APBx prescalers and Flash settings),
* depending on the configuration made in the clock xls tool.
* This function is called at startup just after reset and
* before branch to main program. This call is made inside
* the "startup_stm32f30x.s" file.
*
* - SystemCoreClock variable: Contains the core clock (HCLK), it can be used
* by the user application to setup the SysTick
* timer or configure other parameters.
*
* - SystemCoreClockUpdate(): Updates the variable SystemCoreClock and must
* be called whenever the core clock is changed
* during program execution.
*
* 2. After each device reset the HSI (8 MHz) is used as system clock source.
* Then SystemInit() function is called, in "startup_stm32f30x.s" file, to
* configure the system clock before to branch to main program.
*
* 3. If the system clock source selected by user fails to startup, the SystemInit()
* function will do nothing and HSI still used as system clock source. User can
* add some code to deal with this issue inside the SetSysClock() function.
*
* 4. The default value of HSE crystal is set to 8MHz, refer to "HSE_VALUE" define
* in "stm32f30x.h" file. When HSE is used as system clock source, directly or
* through PLL, and you are using different crystal you have to adapt the HSE
* value to your own configuration.
*
* 5. This file configures the system clock as follows:
*=============================================================================
* Supported STM32F30x device
*-----------------------------------------------------------------------------
* System Clock source | PLL (HSE)
*-----------------------------------------------------------------------------
* SYSCLK(Hz) | 72000000
*-----------------------------------------------------------------------------
* HCLK(Hz) | 72000000
*-----------------------------------------------------------------------------
* AHB Prescaler | 1
*-----------------------------------------------------------------------------
* APB2 Prescaler | 1
*-----------------------------------------------------------------------------
* APB1 Prescaler | 2
*-----------------------------------------------------------------------------
* HSE Frequency(Hz) | 8000000
*----------------------------------------------------------------------------
* PLLMUL | 9
*-----------------------------------------------------------------------------
* PREDIV | 1
*-----------------------------------------------------------------------------
* USB Clock | DISABLE
*-----------------------------------------------------------------------------
* Flash Latency(WS) | 2
*-----------------------------------------------------------------------------
* Prefetch Buffer | ON
*-----------------------------------------------------------------------------
*=============================================================================
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2012 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2
*
* 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.
*
******************************************************************************
*/
/** @addtogroup CMSIS
* @{
*/
/** @addtogroup stm32f30x_system
* @{
*/
/** @addtogroup STM32F30x_System_Private_Includes
* @{
*/
#include "stm32f30x.h"
/**
* @}
*/
/** @addtogroup STM32F30x_System_Private_TypesDefinitions
* @{
*/
/**
* @}
*/
/** @addtogroup STM32F30x_System_Private_Defines
* @{
*/
/*!< Uncomment the following line if you need to relocate your vector Table in
Internal SRAM. */
/* #define VECT_TAB_SRAM */
#define VECT_TAB_OFFSET 0x0 /*!< Vector Table base offset field.
This value must be a multiple of 0x200. */
/**
* @}
*/
/** @addtogroup STM32F30x_System_Private_Macros
* @{
*/
/**
* @}
*/
/** @addtogroup STM32F30x_System_Private_Variables
* @{
*/
uint32_t SystemCoreClock = 72000000;
__I uint8_t AHBPrescTable[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9 };
/**
* @}
*/
/** @addtogroup STM32F30x_System_Private_FunctionPrototypes
* @{
*/
static void SetSysClock(void);
/**
* @}
*/
/** @addtogroup STM32F30x_System_Private_Functions
* @{
*/
/**
* @brief Setup the microcontroller system
* Initialize the Embedded Flash Interface, the PLL and update the
* SystemFrequency variable.
* @param None
* @retval None
*/
void SystemInit(void)
{
/* FPU settings ------------------------------------------------------------*/
#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
SCB->CPACR |= ((3UL << 10 * 2) | (3UL << 11 * 2)); /* set CP10 and CP11 Full Access */
#endif
/* Reset the RCC clock configuration to the default reset state ------------*/
/* Set HSION bit */
RCC->CR |= (uint32_t)0x00000001;
/* Reset CFGR register */
RCC->CFGR &= 0xF87FC00C;
/* Reset HSEON, CSSON and PLLON bits */
RCC->CR &= (uint32_t)0xFEF6FFFF;
/* Reset HSEBYP bit */
RCC->CR &= (uint32_t)0xFFFBFFFF;
/* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE bits */
RCC->CFGR &= (uint32_t)0xFF80FFFF;
/* Reset PREDIV1[3:0] bits */
RCC->CFGR2 &= (uint32_t)0xFFFFFFF0;
/* Reset USARTSW[1:0], I2CSW and TIMs bits */
RCC->CFGR3 &= (uint32_t)0xFF00FCCC;
/* Disable all interrupts */
RCC->CIR = 0x00000000;
/* Configure the System clock source, PLL Multiplier and Divider factors,
AHB/APBx prescalers and Flash settings ----------------------------------*/
SetSysClock();
#ifdef VECT_TAB_SRAM
SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */
#else
SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */
#endif
}
/**
* @brief Update SystemCoreClock variable according to Clock Register Values.
* The SystemCoreClock variable contains the core clock (HCLK), it can
* be used by the user application to setup the SysTick timer or configure
* other parameters.
*
* @note Each time the core clock (HCLK) changes, this function must be called
* to update SystemCoreClock variable value. Otherwise, any configuration
* based on this variable will be incorrect.
*
* @note - The system frequency computed by this function is not the real
* frequency in the chip. It is calculated based on the predefined
* constant and the selected clock source:
*
* - If SYSCLK source is HSI, SystemCoreClock will contain the HSI_VALUE(*)
*
* - If SYSCLK source is HSE, SystemCoreClock will contain the HSE_VALUE(**)
*
* - If SYSCLK source is PLL, SystemCoreClock will contain the HSE_VALUE(**)
* or HSI_VALUE(*) multiplied/divided by the PLL factors.
*
* (*) HSI_VALUE is a constant defined in stm32f30x.h file (default value
* 8 MHz) but the real value may vary depending on the variations
* in voltage and temperature.
*
* (**) HSE_VALUE is a constant defined in stm32f30x.h file (default value
* 8 MHz), user has to ensure that HSE_VALUE is same as the real
* frequency of the crystal used. Otherwise, this function may
* have wrong result.
*
* - The result of this function could be not correct when using fractional
* value for HSE crystal.
*
* @param None
* @retval None
*/
void SystemCoreClockUpdate(void)
{
uint32_t tmp = 0, pllmull = 0, pllsource = 0, prediv1factor = 0;
/* Get SYSCLK source -------------------------------------------------------*/
tmp = RCC->CFGR & RCC_CFGR_SWS;
switch (tmp) {
case 0x00: /* HSI used as system clock */
SystemCoreClock = HSI_VALUE;
break;
case 0x04: /* HSE used as system clock */
SystemCoreClock = HSE_VALUE;
break;
case 0x08: /* PLL used as system clock */
/* Get PLL clock source and multiplication factor ----------------------*/
pllmull = RCC->CFGR & RCC_CFGR_PLLMULL;
pllsource = RCC->CFGR & RCC_CFGR_PLLSRC;
pllmull = (pllmull >> 18) + 2;
if (pllsource == 0x00) {
/* HSI oscillator clock divided by 2 selected as PLL clock entry */
SystemCoreClock = (HSI_VALUE >> 1) * pllmull;
} else {
prediv1factor = (RCC->CFGR2 & RCC_CFGR2_PREDIV1) + 1;
/* HSE oscillator clock selected as PREDIV1 clock entry */
SystemCoreClock = (HSE_VALUE / prediv1factor) * pllmull;
}
break;
default: /* HSI used as system clock */
SystemCoreClock = HSI_VALUE;
break;
}
/* Compute HCLK clock frequency ----------------*/
/* Get HCLK prescaler */
tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4)];
/* HCLK clock frequency */
SystemCoreClock >>= tmp;
}
/**
* @brief Configures the System clock source, PLL Multiplier and Divider factors,
* AHB/APBx prescalers and Flash settings
* @note This function should be called only once the RCC clock configuration
* is reset to the default reset state (done in SystemInit() function).
* @param None
* @retval None
*/
static void SetSysClock(void)
{
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
/******************************************************************************/
/* PLL (clocked by HSE) used as System clock source */
/******************************************************************************/
/* SYSCLK, HCLK, PCLK2 and PCLK1 configuration -----------*/
/* Enable HSE */
#ifdef PIOS_RCC_HSE_BYPASS
RCC->CR |= ((uint32_t)RCC_CR_HSEON | RCC_CR_HSEBYP);
#else
RCC->CR |= ((uint32_t)RCC_CR_HSEON);
#endif /* PIOS_HSE_BYPASS */
/* Wait till HSE is ready and if Time out is reached exit */
do {
HSEStatus = RCC->CR & RCC_CR_HSERDY;
StartUpCounter++;
} while ((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
if ((RCC->CR & RCC_CR_HSERDY) != RESET) {
HSEStatus = (uint32_t)0x01;
} else {
HSEStatus = (uint32_t)0x00;
}
if (HSEStatus == (uint32_t)0x01) {
/* Enable Prefetch Buffer and set Flash Latency */
FLASH->ACR = FLASH_ACR_PRFTBE | (uint32_t)FLASH_ACR_LATENCY_1;
/* HCLK = SYSCLK / 1 */
RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
/* PCLK2 = HCLK / 1 */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
/* PCLK1 = HCLK / 2 */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;
/* PLL configuration */
RCC->CFGR &= (uint32_t)((uint32_t) ~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL));
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_PREDIV1 | RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLMULL9);
/* Enable PLL */
RCC->CR |= RCC_CR_PLLON;
/* Wait till PLL is ready */
while ((RCC->CR & RCC_CR_PLLRDY) == 0) {}
/* Select PLL as system clock source */
RCC->CFGR &= (uint32_t)((uint32_t) ~(RCC_CFGR_SW));
RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;
/* Wait till PLL is used as system clock source */
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)RCC_CFGR_SWS_PLL) {}
} else { /* If HSE fails to start-up, the application will have wrong clock
configuration. User can add here some code to deal with this error */
}
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View File

@ -0,0 +1,233 @@
/**
******************************************************************************
* @addtogroup PIOS PIOS Core hardware abstraction layer
* @{
*
* @file vectors_stm32f30x.c
* @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017.
* Tau Labs, http://taulabs.org, Copyright (C) 2012-2013
* The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
* @brief C based vectors for F3
* @see The GNU Public License (GPL) Version 3
*
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/** interrupt handler */
typedef void (vector)(void);
/** default interrupt handler */
static void default_io_handler(void)
{
asm volatile ("BKPT #01");
for (;;) {
;
}
}
/** prototypes an interrupt handler */
#define HANDLER(_name) extern vector _name __attribute__((weak, alias("default_io_handler")))
HANDLER(Reserved_IRQHandler); // Reserved
HANDLER(WWDG_IRQHandler); // Window WatchDog
HANDLER(PVD_IRQHandler); // PVD through EXTI Line detection
HANDLER(TAMP_STAMP_IRQHandler); // Tamper and TimeStamps through the EXTI line
HANDLER(RTC_WKUP_IRQHandler); // RTC Wakeup through the EXTI line
HANDLER(FLASH_IRQHandler); // FLASH
HANDLER(RCC_IRQHandler); // RCC
HANDLER(EXTI0_IRQHandler); // EXTI Line0
HANDLER(EXTI1_IRQHandler); // EXTI Line1
HANDLER(EXTI2_TS_IRQHandler); // EXTI Line2 and Touch Sense Interrupt
HANDLER(EXTI3_IRQHandler); // EXTI Line3
HANDLER(EXTI4_IRQHandler); // EXTI Line4
HANDLER(DMA1_Channel1_IRQHandler); // DMA1 Channel 1
HANDLER(DMA1_Channel2_IRQHandler); // DMA1 Channel 2
HANDLER(DMA1_Channel3_IRQHandler); // DMA1 Channel 3
HANDLER(DMA1_Channel4_IRQHandler); // DMA1 Channel 4
HANDLER(DMA1_Channel5_IRQHandler); // DMA1 Channel 5
HANDLER(DMA1_Channel6_IRQHandler); // DMA1 Channel 6
HANDLER(DMA1_Channel7_IRQHandler); // DMA1 Channel 7
HANDLER(ADC1_2_IRQHandler); // ADC1 and ADC2
HANDLER(USB_HP_CAN1_TX_IRQHandler); // USB Device High Priority or CAN1 TX
HANDLER(USB_LP_CAN1_RX0_IRQHandler); // USB Device Low Priority or CAN1 RX0
HANDLER(CAN1_RX1_IRQHandler); // CAN1 RX1
HANDLER(CAN1_SCE_IRQHandler); // CAN1 SCE
HANDLER(EXTI9_5_IRQHandler); // External Line[9:5]s
HANDLER(TIM1_BRK_TIM15_IRQHandler); // TIM1 Break and TIM15
HANDLER(TIM1_UP_TIM16_IRQHandler); // TIM1 Update and TIM16
HANDLER(TIM1_TRG_COM_TIM17_IRQHandler); // TIM1 Trigger and Commutation and TIM17
HANDLER(TIM1_CC_IRQHandler); // TIM1 Capture Compare
HANDLER(TIM2_IRQHandler); // TIM2
HANDLER(TIM3_IRQHandler); // TIM3
HANDLER(TIM4_IRQHandler); // TIM4
HANDLER(I2C1_EV_EXTI23_IRQHandler); // I2C1 Event and EXTI23
HANDLER(I2C1_ER_IRQHandler); // I2C1 Error
HANDLER(I2C2_EV_EXTI24_IRQHandler); // I2C2 Event and EXTI24
HANDLER(I2C2_ER_IRQHandler); // I2C2 Error
HANDLER(SPI1_IRQHandler); // SPI1
HANDLER(SPI2_IRQHandler); // SPI2
HANDLER(USART1_EXTI25_IRQHandler); // USART1 and EXTI25
HANDLER(USART2_EXTI26_IRQHandler); // USART2 and EXTI26
HANDLER(USART3_EXTI28_IRQHandler); // USART3 and EXTI28
HANDLER(EXTI15_10_IRQHandler); // External Line[15:10]s
HANDLER(RTC_Alarm_IRQHandler); // RTC Alarm (A and B) through EXTI Line
HANDLER(USB_WKUP_IRQHandler); // USB FS Wakeup through EXTI line
HANDLER(TIM8_BRK_IRQHandler); // TIM8 Break
HANDLER(TIM8_UP_IRQHandler); // TIM8 Update
HANDLER(TIM8_TRG_COM_IRQHandler); // TIM8 Trigger and Commutation
HANDLER(TIM8_CC_IRQHandler); // TIM8 Capture Compare
HANDLER(ADC3_IRQHandler); // ADC3
HANDLER(SPI3_IRQHandler); // SPI3
HANDLER(UART4_EXTI34_IRQHandler); // UART4 and EXTI34
HANDLER(UART5_EXTI35_IRQHandler); // UART5 and EXTI35
HANDLER(TIM6_DAC_IRQHandler); // TIM6 and DAC1&2 underrun errors
HANDLER(TIM7_IRQHandler); // TIM7
HANDLER(DMA2_Channel1_IRQHandler); // DMA2 Channel 1
HANDLER(DMA2_Channel2_IRQHandler); // DMA2 Channel 2
HANDLER(DMA2_Channel3_IRQHandler); // DMA2 Channel 3
HANDLER(DMA2_Channel4_IRQHandler); // DMA2 Channel 4
HANDLER(DMA2_Channel5_IRQHandler); // DMA2 Channel 5
HANDLER(ADC4_IRQHandler); // ADC4
HANDLER(COMP1_2_3_IRQHandler); // COMP1, COMP2 and COMP3
HANDLER(COMP4_5_6_IRQHandler); // COMP4, COMP5 and COMP6
HANDLER(COMP7_IRQHandler); // COMP7
HANDLER(USB_HP_IRQHandler); // USB High Priority remap
HANDLER(USB_LP_IRQHandler); // USB Low Priority remap
HANDLER(USB_WKUP_RMP_IRQHandler); // USB Wakup remap
HANDLER(FPU_IRQHandler); // FPU
#if defined(STM32F303xD) || defined(STM32F303xE)
HANDLER(FMC_IRQHandler);
HANDLER(I2C3_EV_IRQHandler);
HANDLER(I2C3_ER_IRQHandler);
HANDLER(TIM20_BRK_IRQHandler);
HANDLER(TIM20_UP_IRQHandler);
HANDLER(TIM20_TRG_COM_IRQHandler);
HANDLER(TIM20_CC_IRQHandler);
HANDLER(SPI4_IRQHandler);
#endif /* defined(STM32F303xD) || defined(STM32F303xE) */
/** stm32f30x interrupt vector table */
vector *io_vectors[] __attribute__((section(".io_vectors"))) = {
WWDG_IRQHandler, // Window WatchDog
PVD_IRQHandler, // PVD through EXTI Line detection
TAMP_STAMP_IRQHandler, // Tamper and TimeStamps through the EXTI line
RTC_WKUP_IRQHandler, // RTC Wakeup through the EXTI line
FLASH_IRQHandler, // FLASH
RCC_IRQHandler, // RCC
EXTI0_IRQHandler, // EXTI Line0
EXTI1_IRQHandler, // EXTI Line1
EXTI2_TS_IRQHandler, // EXTI Line2 and Touch Sense Interrupt
EXTI3_IRQHandler, // EXTI Line3
EXTI4_IRQHandler, // EXTI Line4
DMA1_Channel1_IRQHandler, // DMA1 Channel 1
DMA1_Channel2_IRQHandler, // DMA1 Channel 2
DMA1_Channel3_IRQHandler, // DMA1 Channel 3
DMA1_Channel4_IRQHandler, // DMA1 Channel 4
DMA1_Channel5_IRQHandler, // DMA1 Channel 5
DMA1_Channel6_IRQHandler, // DMA1 Channel 6
DMA1_Channel7_IRQHandler, // DMA1 Channel 7
ADC1_2_IRQHandler, // ADC1 and ADC2
USB_HP_CAN1_TX_IRQHandler, // USB Device High Priority or CAN1 TX
USB_LP_CAN1_RX0_IRQHandler, // USB Device Low Priority or CAN1 RX0
CAN1_RX1_IRQHandler, // CAN1 RX1
CAN1_SCE_IRQHandler, // CAN1 SCE
EXTI9_5_IRQHandler, // External Line[9:5]s
TIM1_BRK_TIM15_IRQHandler, // TIM1 Break and TIM15
TIM1_UP_TIM16_IRQHandler, // TIM1 Update and TIM16
TIM1_TRG_COM_TIM17_IRQHandler, // TIM1 Trigger and Commutation and TIM17
TIM1_CC_IRQHandler, // TIM1 Capture Compare
TIM2_IRQHandler, // TIM2
TIM3_IRQHandler, // TIM3
TIM4_IRQHandler, // TIM4
I2C1_EV_EXTI23_IRQHandler, // I2C1 Event and EXTI23
I2C1_ER_IRQHandler, // I2C1 Error
I2C2_EV_EXTI24_IRQHandler, // I2C2 Event and EXTI24
I2C2_ER_IRQHandler, // I2C2 Error
SPI1_IRQHandler, // SPI1
SPI2_IRQHandler, // SPI2
USART1_EXTI25_IRQHandler, // USART1 and EXTI25
USART2_EXTI26_IRQHandler, // USART2 and EXTI26
USART3_EXTI28_IRQHandler, // USART3 and EXTI28
EXTI15_10_IRQHandler, // External Line[15:10]s
RTC_Alarm_IRQHandler, // RTC Alarm (A and B) through EXTI Line
USB_WKUP_IRQHandler, // USB FS Wakeup through EXTI line
TIM8_BRK_IRQHandler, // TIM8 Break
TIM8_UP_IRQHandler, // TIM8 Update
TIM8_TRG_COM_IRQHandler, // TIM8 Trigger and Commutation
TIM8_CC_IRQHandler, // TIM8 Capture Compare
ADC3_IRQHandler, // ADC3
#if defined(STM32F303xD) || defined(STM32F303xE)
FMC_IRQHandler, // FMC_IRQHandler (Available in STM32F303xD/E only)
#else
Reserved_IRQHandler, // reserved
#endif
Reserved_IRQHandler, // reserved
Reserved_IRQHandler, // reserved
SPI3_IRQHandler, // SPI3
UART4_EXTI34_IRQHandler, // UART4 and EXTI34
UART5_EXTI35_IRQHandler, // UART5 and EXTI35
TIM6_DAC_IRQHandler, // TIM6 and DAC1&2 underrun errors
TIM7_IRQHandler, // TIM7
DMA2_Channel1_IRQHandler, // DMA2 Channel 1
DMA2_Channel2_IRQHandler, // DMA2 Channel 2
DMA2_Channel3_IRQHandler, // DMA2 Channel 3
DMA2_Channel4_IRQHandler, // DMA2 Channel 4
DMA2_Channel5_IRQHandler, // DMA2 Channel 5
ADC4_IRQHandler, // ADC4
Reserved_IRQHandler, // reserved
Reserved_IRQHandler, // reserved
COMP1_2_3_IRQHandler, // COMP1, COMP2 and COMP3
COMP4_5_6_IRQHandler, // COMP4, COMP5 and COMP6
COMP7_IRQHandler, // COMP7
Reserved_IRQHandler, // reserved
Reserved_IRQHandler, // reserved
Reserved_IRQHandler, // reserved
Reserved_IRQHandler, // reserved
Reserved_IRQHandler, // reserved
#if defined(STM32F303xD) || defined(STM32F303xE)
I2C3_EV_IRQHandler, /*!< I2C3 event interrupt */
I2C3_ER_IRQHandler, /*!< I2C3 error interrupt */
#else
Reserved_IRQHandler, // reserved
Reserved_IRQHandler, // reserved
#endif
USB_HP_IRQHandler, // USB High Priority remap
USB_LP_IRQHandler, // USB Low Priority remap
USB_WKUP_RMP_IRQHandler, // USB Wakup remap
#if defined(STM32F303xD) || defined(STM32F303xE)
TIM20_BRK_IRQHandler, /*!< TIM20 Break Interrupt */
TIM20_UP_IRQHandler, /*!< TIM20 Update Interrupt */
TIM20_TRG_COM_IRQHandler, /*!< TIM20 Trigger and Commutation Interrupt */
TIM20_CC_IRQHandler, /*!< TIM20 Capture Compare Interrupt */
#else
Reserved_IRQHandler, // reserved
Reserved_IRQHandler, // reserved
Reserved_IRQHandler, // reserved
Reserved_IRQHandler, // reserved
#endif
FPU_IRQHandler, // FPU
#if defined(STM32F303xD) || defined(STM32F303xE)
Reserved_IRQHandler,
Reserved_IRQHandler,
SPI4_IRQHandler /*!< SPI4 global Interrupt */
#endif
};
/**
* @}
*/

View File

@ -130,7 +130,7 @@ struct pios_ws2811_cfg {
struct stm32_irq irq;
};
void PIOS_WS2811_Init(const struct pios_ws2811_cfg *ws2811_cfg, const struct pios_ws2811_pin_cfg *ws2811_pin_cfg);
void PIOS_WS2811_Init(uint32_t *dev_id, const struct pios_ws2811_cfg *ws2811_cfg, const struct pios_ws2811_pin_cfg *ws2811_pin_cfg);
void PIOS_WS2811_DMA_irq_handler();
#endif /* PIOS_WS2811_H_ */

View File

@ -15,7 +15,7 @@ LINKER_SCRIPTS_COMPAT = $(PIOS_DEVLIB)link_$(BOARD)_fw_memory.ld \
$(PIOS_DEVLIB)link_$(BOARD)_sections_compat.ld
# Compiler options implied by the F4xx
CDEFS += -DSTM32F4XX
CDEFS += -DSTM32F4XX -DSTM32F4
ifeq ($(CHIPFAMILY),STM32F427_437xx)
CDEFS += -DPIOS_TARGET_PROVIDES_FAST_HEAP
#large heap support must be enabled if SRAM > 128K

View File

@ -159,7 +159,7 @@ static bool i2c_adapter_wait_for_stopped(struct pios_i2c_adapter *i2c_adapter);
static void i2c_adapter_reset_bus(struct pios_i2c_adapter *i2c_adapter);
static void i2c_adapter_log_fault(enum pios_i2c_error_type type);
static bool i2c_adapter_callback_handler(struct pios_i2c_adapter *i2c_adapter);
static bool i2c_adapter_callback_handler(struct pios_i2c_adapter *i2c_adapter, signed portBASE_TYPE *pxHigherPriorityTaskWoken);
static const struct i2c_adapter_transition i2c_adapter_transitions[I2C_STATE_NUM_STATES] = {
[I2C_STATE_FSM_FAULT] = {
@ -420,18 +420,19 @@ static void go_stopping(struct pios_i2c_adapter *i2c_adapter)
I2C_ITConfig(i2c_adapter->cfg->regs, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR, DISABLE);
if (i2c_adapter->callback) {
i2c_adapter_callback_handler(i2c_adapter, &pxHigherPriorityTaskWoken);
} else {
#ifdef USE_FREERTOS
if (xSemaphoreGiveFromISR(i2c_adapter->sem_ready, &pxHigherPriorityTaskWoken) != pdTRUE) {
#if defined(I2C_HALT_ON_ERRORS)
PIOS_DEBUG_Assert(0);
#endif
}
portEND_SWITCHING_ISR(pxHigherPriorityTaskWoken); /* FIXME: is this the right place for this? */
#endif /* USE_FREERTOS */
if (i2c_adapter->callback) {
i2c_adapter_callback_handler(i2c_adapter);
}
portEND_SWITCHING_ISR(pxHigherPriorityTaskWoken); /* FIXME: is this the right place for this? */
}
@ -853,18 +854,8 @@ static bool i2c_adapter_fsm_terminated(struct pios_i2c_adapter *i2c_adapter)
uint32_t i2c_cb_count = 0;
static bool i2c_adapter_callback_handler(struct pios_i2c_adapter *i2c_adapter)
static bool i2c_adapter_callback_handler(struct pios_i2c_adapter *i2c_adapter, signed portBASE_TYPE *pxHigherPriorityTaskWoken)
{
bool semaphore_success = true;
/* Wait for the transfer to complete */
#ifdef USE_FREERTOS
portTickType timeout;
timeout = i2c_adapter->cfg->transfer_timeout_ms / portTICK_RATE_MS;
semaphore_success &= (xSemaphoreTake(i2c_adapter->sem_ready, timeout) == pdTRUE);
xSemaphoreGive(i2c_adapter->sem_ready);
#endif /* USE_FREERTOS */
/* transfer_timeout_ticks is set by PIOS_I2C_Transfer_Callback */
/* Spin waiting for the transfer to finish */
while (!i2c_adapter_fsm_terminated(i2c_adapter)) {
@ -885,17 +876,10 @@ static bool i2c_adapter_callback_handler(struct pios_i2c_adapter *i2c_adapter)
i2c_adapter_fsm_init(i2c_adapter);
}
// Execute user supplied function
i2c_adapter->callback();
i2c_cb_count++;
#ifdef USE_FREERTOS
/* Unlock the bus */
xSemaphoreGive(i2c_adapter->sem_busy);
if (!semaphore_success) {
i2c_timeout_counter++;
}
xSemaphoreGiveFromISR(i2c_adapter->sem_busy, pxHigherPriorityTaskWoken);
#else
PIOS_IRQ_Disable();
i2c_adapter->busy = 0;
@ -903,7 +887,14 @@ static bool i2c_adapter_callback_handler(struct pios_i2c_adapter *i2c_adapter)
#endif /* USE_FREERTOS */
return (!i2c_adapter->bus_error) && semaphore_success;
// Execute user supplied function
if (i2c_adapter->callback()) {
*pxHigherPriorityTaskWoken = pdTRUE;
}
i2c_cb_count++;
return !i2c_adapter->bus_error;
}
@ -1149,7 +1140,31 @@ int32_t PIOS_I2C_Transfer(uint32_t i2c_id, const struct pios_i2c_txn txn_list[],
0;
}
int32_t PIOS_I2C_Transfer_Callback(uint32_t i2c_id, const struct pios_i2c_txn txn_list[], uint32_t num_txns, void *callback)
static int32_t PIOS_I2C_Transfer_Callback_Internal(struct pios_i2c_adapter *i2c_adapter, const struct pios_i2c_txn txn_list[], uint32_t num_txns, pios_i2c_callback callback)
{
PIOS_DEBUG_Assert(i2c_adapter->curr_state == I2C_STATE_STOPPED);
i2c_adapter->first_txn = &txn_list[0];
i2c_adapter->last_txn = &txn_list[num_txns - 1];
i2c_adapter->active_txn = i2c_adapter->first_txn;
i2c_adapter->bus_error = false;
i2c_adapter->nack = false;
i2c_adapter->callback = callback;
// Estimate bytes of transmission. Per txns: 1 adress byte + length
i2c_adapter->transfer_timeout_ticks = num_txns;
for (uint32_t i = 0; i < num_txns; i++) {
i2c_adapter->transfer_timeout_ticks += txn_list[i].len;
}
// timeout if it takes eight times the expected time
i2c_adapter->transfer_timeout_ticks <<= 3;
i2c_adapter_inject_event(i2c_adapter, I2C_EVENT_START);
return 0;
}
int32_t PIOS_I2C_Transfer_Callback(uint32_t i2c_id, const struct pios_i2c_txn txn_list[], uint32_t num_txns, pios_i2c_callback callback)
{
struct pios_i2c_adapter *i2c_adapter = (struct pios_i2c_adapter *)i2c_id;
@ -1162,8 +1177,6 @@ int32_t PIOS_I2C_Transfer_Callback(uint32_t i2c_id, const struct pios_i2c_txn tx
PIOS_DEBUG_Assert(txn_list);
PIOS_DEBUG_Assert(num_txns);
bool semaphore_success = true;
#ifdef USE_FREERTOS
/* Lock the bus */
portTickType timeout;
@ -1172,37 +1185,54 @@ int32_t PIOS_I2C_Transfer_Callback(uint32_t i2c_id, const struct pios_i2c_txn tx
return -2;
}
#else
PIOS_IRQ_Disable();
if (i2c_adapter->busy) {
PIOS_IRQ_Enable();
return -2;
}
i2c_adapter->busy = 1;
PIOS_IRQ_Enable();
#endif /* USE_FREERTOS */
PIOS_DEBUG_Assert(i2c_adapter->curr_state == I2C_STATE_STOPPED);
return PIOS_I2C_Transfer_Callback_Internal(i2c_adapter, txn_list, num_txns, callback);
}
i2c_adapter->first_txn = &txn_list[0];
i2c_adapter->last_txn = &txn_list[num_txns - 1];
i2c_adapter->active_txn = i2c_adapter->first_txn;
int32_t PIOS_I2C_Transfer_CallbackFromISR(uint32_t i2c_id, const struct pios_i2c_txn txn_list[], uint32_t num_txns, pios_i2c_callback callback, bool *woken)
{
// FIXME: only supports transfer sizes up to 255 bytes
struct pios_i2c_adapter *i2c_adapter = (struct pios_i2c_adapter *)i2c_id;
bool valid = PIOS_I2C_validate(i2c_adapter);
PIOS_Assert(valid)
PIOS_DEBUG_Assert(txn_list);
PIOS_DEBUG_Assert(num_txns);
#ifdef USE_FREERTOS
/* Make sure the done/ready semaphore is consumed before we start */
semaphore_success &= (xSemaphoreTake(i2c_adapter->sem_ready, timeout) == pdTRUE);
#endif
signed portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
// used in the i2c_adapter_callback_handler function
// Estimate bytes of transmission. Per txns: 1 adress byte + length
i2c_adapter->transfer_timeout_ticks = num_txns;
for (uint32_t i = 0; i < num_txns; i++) {
i2c_adapter->transfer_timeout_ticks += txn_list[i].len;
/* Lock the bus */
bool locked = xSemaphoreTakeFromISR(i2c_adapter->sem_busy, &xHigherPriorityTaskWoken) == pdTRUE;
if (xHigherPriorityTaskWoken == pdTRUE) {
*woken = true;
}
// timeout if it takes eight times the expected time
i2c_adapter->transfer_timeout_ticks <<= 3;
i2c_adapter->callback = callback;
i2c_adapter->bus_error = false;
i2c_adapter_inject_event(i2c_adapter, I2C_EVENT_START);
if (!locked) {
return -2;
}
#else
PIOS_IRQ_Disable();
if (i2c_adapter->busy) {
PIOS_IRQ_Enable();
return -2;
}
i2c_adapter->busy = 1;
PIOS_IRQ_Enable();
#endif /* USE_FREERTOS */
return !semaphore_success ? -2 : 0;
return PIOS_I2C_Transfer_Callback_Internal(i2c_adapter, txn_list, num_txns, callback);
}
void PIOS_I2C_EV_IRQ_Handler(uint32_t i2c_id)

View File

@ -204,12 +204,17 @@ int32_t PIOS_SYS_Reset(void)
PIOS_IRQ_Disable();
// turn off all board LEDs
#if defined(PIOS_LED_HEARTBEAT)
#ifdef PIOS_INCLUDE_LED
# ifdef PIOS_LED_HEARTBEAT
PIOS_LED_Off(PIOS_LED_HEARTBEAT);
# endif /* PIOS_LED_HEARTBEAT */
#if defined(PIOS_LED_ALARM)
# ifdef PIOS_LED_ALARM
PIOS_LED_Off(PIOS_LED_ALARM);
# endif /* PIOS_LED_ALARM */
# ifdef PIOS_BUZZER_ALARM
PIOS_LED_Off(PIOS_BUZZER_ALARM);
# endif /* PIOS_BUZZER_ALARM */
#endif /* PIOS_INCLUDE_LED */
/* XXX F10x port resets most (but not all) peripherals ... do we care? */

View File

@ -72,6 +72,7 @@ struct pios_usart_dev {
uint32_t rx_in_context;
pios_com_callback tx_out_cb;
uint32_t tx_out_context;
bool config_locked;
uint8_t irq_channel;
};
@ -196,6 +197,46 @@ int32_t PIOS_USART_Init(uint32_t *usart_id, const struct pios_usart_cfg *cfg)
PIOS_DEBUG_Assert(usart_id);
PIOS_DEBUG_Assert(cfg);
uint32_t *local_id;
uint8_t irq_channel;
switch ((uint32_t)cfg->regs) {
case (uint32_t)USART1:
local_id = &PIOS_USART_1_id;
irq_channel = USART1_IRQn;
break;
case (uint32_t)USART2:
local_id = &PIOS_USART_2_id;
irq_channel = USART2_IRQn;
break;
#if !defined(STM32F411xE)
case (uint32_t)USART3:
local_id = &PIOS_USART_3_id;
irq_channel = USART3_IRQn;
break;
case (uint32_t)UART4:
local_id = &PIOS_USART_4_id;
irq_channel = UART4_IRQn;
break;
case (uint32_t)UART5:
local_id = &PIOS_USART_5_id;
irq_channel = UART5_IRQn;
break;
#endif /* STM32F411xE */
case (uint32_t)USART6:
local_id = &PIOS_USART_6_id;
irq_channel = USART6_IRQn;
break;
default:
goto out_fail;
}
if (*local_id) {
/* this port is already open */
*usart_id = *local_id;
return 0;
}
struct pios_usart_dev *usart_dev;
usart_dev = (struct pios_usart_dev *)PIOS_USART_alloc();
@ -205,6 +246,7 @@ int32_t PIOS_USART_Init(uint32_t *usart_id, const struct pios_usart_cfg *cfg)
/* Bind the configuration to the device instance */
usart_dev->cfg = cfg;
usart_dev->irq_channel = irq_channel;
/* Initialize the comm parameter structure */
USART_StructInit(&usart_dev->init); // 9600 8n1
@ -236,38 +278,10 @@ int32_t PIOS_USART_Init(uint32_t *usart_id, const struct pios_usart_cfg *cfg)
}
#endif
/* Configure USART Interrupts */
switch ((uint32_t)usart_dev->cfg->regs) {
case (uint32_t)USART1:
PIOS_USART_1_id = (uint32_t)usart_dev;
usart_dev->irq_channel = USART1_IRQn;
break;
case (uint32_t)USART2:
PIOS_USART_2_id = (uint32_t)usart_dev;
usart_dev->irq_channel = USART2_IRQn;
break;
#if !defined(STM32F411xE)
case (uint32_t)USART3:
PIOS_USART_3_id = (uint32_t)usart_dev;
usart_dev->irq_channel = USART3_IRQn;
break;
case (uint32_t)UART4:
PIOS_USART_4_id = (uint32_t)usart_dev;
usart_dev->irq_channel = UART4_IRQn;
break;
case (uint32_t)UART5:
PIOS_USART_5_id = (uint32_t)usart_dev;
usart_dev->irq_channel = UART5_IRQn;
break;
#endif /* STM32F411xE */
case (uint32_t)USART6:
PIOS_USART_6_id = (uint32_t)usart_dev;
usart_dev->irq_channel = USART6_IRQn;
break;
}
PIOS_USART_SetIrqPrio(usart_dev, PIOS_IRQ_PRIO_MID);
*usart_id = (uint32_t)usart_dev;
*local_id = (uint32_t)usart_dev;
PIOS_USART_SetIrqPrio(usart_dev, PIOS_IRQ_PRIO_MID);
return 0;
@ -303,7 +317,15 @@ static void PIOS_USART_Setup(struct pios_usart_dev *usart_dev)
}
/* Write new configuration */
USART_Init(usart_dev->cfg->regs, &usart_dev->init);
{ // fix parity stuff
USART_InitTypeDef init = usart_dev->init;
if ((init.USART_Parity != USART_Parity_No) && (init.USART_WordLength == USART_WordLength_8b)) {
init.USART_WordLength = USART_WordLength_9b;
}
USART_Init(usart_dev->cfg->regs, &init);
}
/*
* Re enable USART.
@ -345,6 +367,9 @@ static void PIOS_USART_ChangeBaud(uint32_t usart_id, uint32_t baud)
PIOS_Assert(valid);
if (usart_dev->config_locked) {
return;
}
/* Use our working copy of the usart init structure */
usart_dev->init.USART_BaudRate = baud;
@ -374,6 +399,10 @@ static void PIOS_USART_ChangeConfig(uint32_t usart_id,
PIOS_Assert(valid);
if (usart_dev->config_locked) {
return;
}
switch (word_len) {
case PIOS_COM_Word_length_8b:
usart_dev->init.USART_WordLength = USART_WordLength_8b;
@ -575,6 +604,9 @@ static int32_t PIOS_USART_Ioctl(uint32_t usart_id, uint32_t ctl, void *param)
case PIOS_IOCTL_USART_SET_HALFDUPLEX:
USART_HalfDuplexCmd(usart_dev->cfg->regs, *(bool *)param ? ENABLE : DISABLE);
break;
case PIOS_IOCTL_USART_LOCK_CONFIG:
usart_dev->config_locked = *(bool *)param;
break;
default:
return COM_IOCTL_ENOSYS; /* unknown ioctl */
}

View File

@ -163,7 +163,9 @@ static void genericTIM_OCxPreloadConfig(TIM_TypeDef *TIMx, uint16_t TIM_OCPreloa
*
*/
void PIOS_WS2811_Init(const struct pios_ws2811_cfg *ws2811_cfg, const struct pios_ws2811_pin_cfg *ws2811_pin_cfg)
#define PIOS_WS2811_MAGIC 0x00281100
void PIOS_WS2811_Init(uint32_t *dev_id, const struct pios_ws2811_cfg *ws2811_cfg, const struct pios_ws2811_pin_cfg *ws2811_pin_cfg)
{
assert_param(ws2811_cfg);
assert_param(ws2811_pin_cfg);
@ -184,6 +186,10 @@ void PIOS_WS2811_Init(const struct pios_ws2811_cfg *ws2811_cfg, const struct pio
// Setup timers
setupTimer();
setupDMA();
// This is required so client (for example Notify module)
// can test for != 0 to know if device is configured or not.
*dev_id = PIOS_WS2811_MAGIC;
}
void setupTimer()

View File

@ -0,0 +1,19 @@
BOARD_TYPE := 0x04
BOARD_REVISION := 0x03
BOOTLOADER_VERSION := 0x04
HW_TYPE := 0x01
CHIP := STM32F303xC
OPENOCD_JTAG_CONFIG := foss-jtag.revb.cfg
OPENOCD_CONFIG := stm32f3x.cfg
# Note: These must match the values in link_$(BOARD)_memory.ld
BL_BANK_BASE := 0x08000000 # Start of bootloader flash
BL_BANK_SIZE := 0x00004000 # Should include BD_INFO region
FW_BANK_BASE := 0x0800C000 # Start of firmware flash
FW_BANK_SIZE := 0x00034000 # Should include FW_DESC_SIZE (208kB)
FW_DESC_SIZE := 0x00000064
OSCILLATOR_FREQ := 8000000

View File

@ -0,0 +1,860 @@
/**
******************************************************************************
* @file board_hw_defs.c
* @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017.
* The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
* PhoenixPilot, http://github.com/PhoenixPilot, Copyright (C) 2012
*
* @addtogroup OpenPilotSystem OpenPilot System
* @{
* @addtogroup OpenPilotCore OpenPilot Core
* @{
* @brief Defines board specific static initializers for hardware for the CCF3D board.
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#if defined(PIOS_INCLUDE_LED)
#include <pios_led_priv.h>
static const struct pios_gpio pios_leds_cc3d[] = {
[PIOS_LED_HEARTBEAT] = {
.pin = {
.gpio = GPIOB,
.init = {
.GPIO_Pin = GPIO_Pin_3,
.GPIO_Mode = GPIO_Mode_OUT,
.GPIO_OType = GPIO_OType_PP,
.GPIO_Speed = GPIO_Speed_50MHz,
.GPIO_PuPd = GPIO_PuPd_NOPULL,
},
},
// .remap = GPIO_Remap_SWJ_JTAGDisable,
.active_low = true
},
};
static const struct pios_gpio_cfg pios_led_cfg_cc3d = {
.gpios = pios_leds_cc3d,
.num_gpios = NELEMENTS(pios_leds_cc3d),
};
const struct pios_gpio_cfg *PIOS_BOARD_HW_DEFS_GetLedCfg(__attribute__((unused)) uint32_t board_revision)
{
return &pios_led_cfg_cc3d;
}
#endif /* PIOS_INCLUDE_LED */
#if defined(PIOS_INCLUDE_SPI)
#include <pios_spi_priv.h>
/* Gyro interface */
void PIOS_SPI_gyro_irq_handler(void);
void DMA1_Channel2_IRQHandler() __attribute__((alias("PIOS_SPI_gyro_irq_handler")));
void DMA1_Channel3_IRQHandler() __attribute__((alias("PIOS_SPI_gyro_irq_handler")));
static const struct pios_spi_cfg pios_spi_gyro_cfg = {
.regs = SPI1,
.init = {
.SPI_Mode = SPI_Mode_Master,
.SPI_Direction = SPI_Direction_2Lines_FullDuplex,
.SPI_DataSize = SPI_DataSize_8b,
.SPI_NSS = SPI_NSS_Soft,
.SPI_FirstBit = SPI_FirstBit_MSB,
.SPI_CRCPolynomial = 7,
.SPI_CPOL = SPI_CPOL_High,
.SPI_CPHA = SPI_CPHA_2Edge,
.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16, /* 10 Mhz */
},
.use_crc = false,
.dma = {
.ahb_clk = RCC_AHBPeriph_DMA1,
.irq = {
.flags = (DMA1_FLAG_TC2 | DMA1_FLAG_TE2 | DMA1_FLAG_HT2 | DMA1_FLAG_GL2),
.init = {
.NVIC_IRQChannel = DMA1_Channel2_IRQn,
.NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID,
.NVIC_IRQChannelSubPriority = 0,
.NVIC_IRQChannelCmd = ENABLE,
},
},
.rx = {
.channel = DMA1_Channel2,
.init = {
.DMA_PeripheralBaseAddr = (uint32_t)&(SPI1->DR),
.DMA_DIR = DMA_DIR_PeripheralSRC,
.DMA_PeripheralInc = DMA_PeripheralInc_Disable,
.DMA_MemoryInc = DMA_MemoryInc_Enable,
.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte,
.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte,
.DMA_Mode = DMA_Mode_Normal,
.DMA_Priority = DMA_Priority_Medium,
.DMA_M2M = DMA_M2M_Disable,
},
},
.tx = {
.channel = DMA1_Channel3,
.init = {
.DMA_PeripheralBaseAddr = (uint32_t)&(SPI1->DR),
.DMA_DIR = DMA_DIR_PeripheralDST,
.DMA_PeripheralInc = DMA_PeripheralInc_Disable,
.DMA_MemoryInc = DMA_MemoryInc_Enable,
.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte,
.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte,
.DMA_Mode = DMA_Mode_Normal,
.DMA_Priority = DMA_Priority_Medium,
.DMA_M2M = DMA_M2M_Disable,
},
},
},
.remap = GPIO_AF_5,
.sclk = {
.gpio = GPIOA,
.init = {
.GPIO_Pin = GPIO_Pin_5,
.GPIO_Speed = GPIO_Speed_50MHz,
.GPIO_Mode = GPIO_Mode_AF,
.GPIO_OType = GPIO_OType_PP,
.GPIO_PuPd = GPIO_PuPd_NOPULL,
},
},
.miso = {
.gpio = GPIOA,
.init = {
.GPIO_Pin = GPIO_Pin_6,
.GPIO_Speed = GPIO_Speed_50MHz,
.GPIO_Mode = GPIO_Mode_AF,
.GPIO_OType = GPIO_OType_PP,
.GPIO_PuPd = GPIO_PuPd_NOPULL,
},
},
.mosi = {
.gpio = GPIOA,
.init = {
.GPIO_Pin = GPIO_Pin_7,
.GPIO_Speed = GPIO_Speed_50MHz,
.GPIO_Mode = GPIO_Mode_AF,
.GPIO_OType = GPIO_OType_PP,
.GPIO_PuPd = GPIO_PuPd_NOPULL,
},
},
.slave_count = 1,
.ssel = {
{
.gpio = GPIOA,
.init = {
.GPIO_Pin = GPIO_Pin_4,
.GPIO_Speed = GPIO_Speed_50MHz,
.GPIO_Mode = GPIO_Mode_OUT,
.GPIO_OType = GPIO_OType_PP,
.GPIO_PuPd = GPIO_PuPd_UP
},
}
},
};
uint32_t pios_spi_gyro_id;
void PIOS_SPI_gyro_irq_handler(void)
{
/* Call into the generic code to handle the IRQ for this specific device */
PIOS_SPI_IRQ_Handler(pios_spi_gyro_id);
}
/* Flash/Accel Interface
*
* NOTE: Leave this declared as const data so that it ends up in the
* .rodata section (ie. Flash) rather than in the .bss section (RAM).
*/
void PIOS_SPI_flash_accel_irq_handler(void);
void DMA1_Channel4_IRQHandler() __attribute__((alias("PIOS_SPI_flash_accel_irq_handler")));
void DMA1_Channel5_IRQHandler() __attribute__((alias("PIOS_SPI_flash_accel_irq_handler")));
static const struct pios_spi_cfg pios_spi_flash_accel_cfg_cc3d = {
.regs = SPI2,
.init = {
.SPI_Mode = SPI_Mode_Master,
.SPI_Direction = SPI_Direction_2Lines_FullDuplex,
.SPI_DataSize = SPI_DataSize_8b,
.SPI_NSS = SPI_NSS_Soft,
.SPI_FirstBit = SPI_FirstBit_MSB,
.SPI_CRCPolynomial = 7,
.SPI_CPOL = SPI_CPOL_High,
.SPI_CPHA = SPI_CPHA_2Edge,
.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8,
},
.use_crc = false,
.dma = {
.ahb_clk = RCC_AHBPeriph_DMA1,
.irq = {
.flags = (DMA1_FLAG_TC4 | DMA1_FLAG_TE4 | DMA1_FLAG_HT4 | DMA1_FLAG_GL4),
.init = {
.NVIC_IRQChannel = DMA1_Channel4_IRQn,
.NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH,
.NVIC_IRQChannelSubPriority = 0,
.NVIC_IRQChannelCmd = ENABLE,
},
},
.rx = {
.channel = DMA1_Channel4,
.init = {
.DMA_PeripheralBaseAddr = (uint32_t)&(SPI2->DR),
.DMA_DIR = DMA_DIR_PeripheralSRC,
.DMA_PeripheralInc = DMA_PeripheralInc_Disable,
.DMA_MemoryInc = DMA_MemoryInc_Enable,
.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte,
.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte,
.DMA_Mode = DMA_Mode_Normal,
.DMA_Priority = DMA_Priority_High,
.DMA_M2M = DMA_M2M_Disable,
},
},
.tx = {
.channel = DMA1_Channel5,
.init = {
.DMA_PeripheralBaseAddr = (uint32_t)&(SPI2->DR),
.DMA_DIR = DMA_DIR_PeripheralDST,
.DMA_PeripheralInc = DMA_PeripheralInc_Disable,
.DMA_MemoryInc = DMA_MemoryInc_Enable,
.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte,
.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte,
.DMA_Mode = DMA_Mode_Normal,
.DMA_Priority = DMA_Priority_High,
.DMA_M2M = DMA_M2M_Disable,
},
},
},
.remap = GPIO_AF_5,
.sclk = {
.gpio = GPIOB,
.init = {
.GPIO_Pin = GPIO_Pin_13,
.GPIO_Speed = GPIO_Speed_50MHz,
.GPIO_Mode = GPIO_Mode_AF,
.GPIO_OType = GPIO_OType_PP,
.GPIO_PuPd = GPIO_PuPd_NOPULL,
},
},
.miso = {
.gpio = GPIOB,
.init = {
.GPIO_Pin = GPIO_Pin_14,
.GPIO_Speed = GPIO_Speed_50MHz,
.GPIO_Mode = GPIO_Mode_AF, /* NOTE: was GPIO_Mode_IN_FLOATING */
.GPIO_OType = GPIO_OType_PP,
.GPIO_PuPd = GPIO_PuPd_NOPULL,
},
},
.mosi = {
.gpio = GPIOB,
.init = {
.GPIO_Pin = GPIO_Pin_15,
.GPIO_Speed = GPIO_Speed_50MHz,
.GPIO_Mode = GPIO_Mode_AF,
.GPIO_OType = GPIO_OType_PP,
.GPIO_PuPd = GPIO_PuPd_NOPULL,
},
},
.slave_count = 2,
.ssel = {
{
.gpio = GPIOB,
.init = {
.GPIO_Pin = GPIO_Pin_12,
.GPIO_Speed = GPIO_Speed_50MHz,
.GPIO_Mode = GPIO_Mode_OUT,
.GPIO_OType = GPIO_OType_PP,
.GPIO_PuPd = GPIO_PuPd_UP,
}
},{
.gpio = GPIOC,
.init = {
.GPIO_Pin = GPIO_Pin_15,
.GPIO_Speed = GPIO_Speed_50MHz,
.GPIO_Mode = GPIO_Mode_OUT,
.GPIO_OType = GPIO_OType_PP,
.GPIO_PuPd = GPIO_PuPd_UP,
},
}
},
};
static uint32_t pios_spi_flash_accel_id;
void PIOS_SPI_flash_accel_irq_handler(void)
{
/* Call into the generic code to handle the IRQ for this specific device */
PIOS_SPI_IRQ_Handler(pios_spi_flash_accel_id);
}
#endif /* PIOS_INCLUDE_SPI */
#if defined(PIOS_INCLUDE_FLASH)
#include "pios_flashfs_logfs_priv.h"
#include "pios_flash_jedec_priv.h"
static const struct flashfs_logfs_cfg flashfs_m25p_cfg = {
.fs_magic = 0x99abceef,
.total_fs_size = 0x00200000, /* 2M bytes (32 sectors = entire chip) */
.arena_size = 0x00010000, /* 256 * slot size */
.slot_size = 0x00000100, /* 256 bytes */
.start_offset = 0, /* start at the beginning of the chip */
.sector_size = 0x00010000, /* 64K bytes */
.page_size = 0x00000100, /* 256 bytes */
};
#include "pios_flash.h"
#endif /* PIOS_INCLUDE_FLASH */
/*
* ADC system
*/
#if defined(PIOS_INCLUDE_ADC)
#include "pios_adc_priv.h"
extern void PIOS_ADC_handler(void);
void DMA1_Channel1_IRQHandler() __attribute__((alias("PIOS_ADC_handler")));
// Remap the ADC DMA handler to this one
static const struct pios_adc_cfg pios_adc_cfg = {
.dma = {
.ahb_clk = RCC_AHBPeriph_DMA1,
.irq = {
.flags = (DMA1_FLAG_TC1 | DMA1_FLAG_TE1 | DMA1_FLAG_HT1 | DMA1_FLAG_GL1),
.init = {
.NVIC_IRQChannel = DMA1_Channel1_IRQn,
.NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID,
.NVIC_IRQChannelSubPriority = 0,
.NVIC_IRQChannelCmd = ENABLE,
},
},
.rx = {
.channel = DMA1_Channel1,
.init = {
.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR,
.DMA_DIR = DMA_DIR_PeripheralSRC,
.DMA_PeripheralInc = DMA_PeripheralInc_Disable,
.DMA_MemoryInc = DMA_MemoryInc_Enable,
.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word,
.DMA_MemoryDataSize = DMA_MemoryDataSize_Word,
.DMA_Mode = DMA_Mode_Circular,
.DMA_Priority = DMA_Priority_High,
.DMA_M2M = DMA_M2M_Disable,
},
}
},
.half_flag = DMA1_IT_HT1,
.full_flag = DMA1_IT_TC1,
};
void PIOS_ADC_handler()
{
PIOS_ADC_DMA_Handler();
}
#endif /* if defined(PIOS_INCLUDE_ADC) */
#include "pios_tim_priv.h"
static const TIM_TimeBaseInitTypeDef tim_1_2_3_4_time_base = {
.TIM_Prescaler = (PIOS_MASTER_CLOCK / 1000000) - 1,
.TIM_ClockDivision = TIM_CKD_DIV1,
.TIM_CounterMode = TIM_CounterMode_Up,
.TIM_Period = ((1000000 / PIOS_SERVO_UPDATE_HZ) - 1),
.TIM_RepetitionCounter = 0x0000,
};
static const struct pios_tim_clock_cfg tim_1_cfg = {
.timer = TIM1,
.time_base_init = &tim_1_2_3_4_time_base,
.irq = {
.init = {
.NVIC_IRQChannel = TIM1_CC_IRQn,
.NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID,
.NVIC_IRQChannelSubPriority = 0,
.NVIC_IRQChannelCmd = ENABLE,
},
},
};
static const struct pios_tim_clock_cfg tim_2_cfg = {
.timer = TIM2,
.time_base_init = &tim_1_2_3_4_time_base,
.irq = {
.init = {
.NVIC_IRQChannel = TIM2_IRQn,
.NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID,
.NVIC_IRQChannelSubPriority = 0,
.NVIC_IRQChannelCmd = ENABLE,
},
},
};
static const struct pios_tim_clock_cfg tim_3_cfg = {
.timer = TIM3,
.time_base_init = &tim_1_2_3_4_time_base,
.irq = {
.init = {
.NVIC_IRQChannel = TIM3_IRQn,
.NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID,
.NVIC_IRQChannelSubPriority = 0,
.NVIC_IRQChannelCmd = ENABLE,
},
},
};
static const struct pios_tim_clock_cfg tim_4_cfg = {
.timer = TIM4,
.time_base_init = &tim_1_2_3_4_time_base,
.irq = {
.init = {
.NVIC_IRQChannel = TIM4_IRQn,
.NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID,
.NVIC_IRQChannelSubPriority = 0,
.NVIC_IRQChannelCmd = ENABLE,
},
},
};
#include <pios_servo_config.h>
#define GPIO_AF_PA1_TIM2 GPIO_AF_1
#define GPIO_AF_PA0_TIM2 GPIO_AF_1
#define GPIO_AF_PA8_TIM1 GPIO_AF_6
#define GPIO_AF_PA2_TIM2 GPIO_AF_1
#define GPIO_AF_PB6_TIM4 GPIO_AF_2
#define GPIO_AF_PB5_TIM3 GPIO_AF_2
#define GPIO_AF_PB0_TIM3 GPIO_AF_2
#define GPIO_AF_PB1_TIM3 GPIO_AF_2
#define GPIO_AF_PB9_TIM4 GPIO_AF_2
#define GPIO_AF_PB8_TIM4 GPIO_AF_2
#define GPIO_AF_PB7_TIM4 GPIO_AF_2
#define GPIO_AF_PB4_TIM3 GPIO_AF_2
#define GPIO_AF_PB11_TIM2 GPIO_AF_1
static const struct pios_tim_channel pios_tim_rcvrport_all_channels[] = {
TIM_SERVO_CHANNEL_CONFIG(TIM4, 1, B, 6),
TIM_SERVO_CHANNEL_CONFIG(TIM3, 2, B, 5),
TIM_SERVO_CHANNEL_CONFIG(TIM3, 3, B, 0),
TIM_SERVO_CHANNEL_CONFIG(TIM3, 4, B, 1),
TIM_SERVO_CHANNEL_CONFIG(TIM2, 1, A, 0),
TIM_SERVO_CHANNEL_CONFIG(TIM2, 2, A, 1),
};
static const struct pios_tim_channel pios_tim_servoport_rcvrport_pins[] = {
TIM_SERVO_CHANNEL_CONFIG(TIM4, 4, B, 9),
TIM_SERVO_CHANNEL_CONFIG(TIM4, 3, B, 8),
TIM_SERVO_CHANNEL_CONFIG(TIM4, 2, B, 7),
TIM_SERVO_CHANNEL_CONFIG(TIM1, 1, A, 8),
TIM_SERVO_CHANNEL_CONFIG(TIM3, 1, B, 4),
TIM_SERVO_CHANNEL_CONFIG(TIM2, 3, A, 2),
// Receiver port pins
// S3-S6 inputs are used as outputs in this case
TIM_SERVO_CHANNEL_CONFIG(TIM3, 3, B, 0),
TIM_SERVO_CHANNEL_CONFIG(TIM3, 4, B, 1),
TIM_SERVO_CHANNEL_CONFIG(TIM2, 1, A, 0),
TIM_SERVO_CHANNEL_CONFIG(TIM2, 2, A, 1),
};
static const struct pios_tim_channel pios_tim_ppm_flexi_port = TIM_SERVO_CHANNEL_CONFIG(TIM2, 4, B, 11);
#if defined(PIOS_INCLUDE_USART)
#define GPIO_AF_USART1 GPIO_AF_7
#define GPIO_AF_USART3 GPIO_AF_7
#include "pios_usart_priv.h"
#include "pios_usart_config.h"
static const struct pios_usart_cfg pios_usart_main_cfg = USART_CONFIG(USART1, A, 10, A, 9);
static const struct pios_usart_cfg pios_usart_flexi_cfg = USART_CONFIG(USART3, B, 11, B, 10);
#endif /* PIOS_INCLUDE_USART */
#if defined(PIOS_INCLUDE_RTC)
/*
* Realtime Clock (RTC)
*/
#include <pios_rtc_priv.h>
void PIOS_RTC_IRQ_Handler(void);
void RTC_WKUP_IRQHandler() __attribute__((alias("PIOS_RTC_IRQ_Handler")));
static const struct pios_rtc_cfg pios_rtc_main_cfg = {
.clksrc = RCC_RTCCLKSource_HSE_Div32,
.prescaler = 25 - 1, // 8Mhz / 32 / 16 / 25 => 625Hz
.irq = {
.init = {
.NVIC_IRQChannel = RTC_WKUP_IRQn,
.NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_MID,
.NVIC_IRQChannelSubPriority = 0,
.NVIC_IRQChannelCmd = ENABLE,
},
},
};
void PIOS_RTC_IRQ_Handler(void)
{
PIOS_RTC_irq_handler();
}
#endif /* if defined(PIOS_INCLUDE_RTC) */
#if defined(PIOS_INCLUDE_SERVO) && defined(PIOS_INCLUDE_TIM)
/*
* Servo outputs
*/
#include <pios_servo_priv.h>
const struct pios_servo_cfg pios_servo_cfg = {
.tim_oc_init = {
.TIM_OCMode = TIM_OCMode_PWM1,
.TIM_OutputState = TIM_OutputState_Enable,
.TIM_OutputNState = TIM_OutputNState_Disable,
.TIM_Pulse = PIOS_SERVOS_INITIAL_POSITION,
.TIM_OCPolarity = TIM_OCPolarity_High,
.TIM_OCNPolarity = TIM_OCPolarity_High,
.TIM_OCIdleState = TIM_OCIdleState_Reset,
.TIM_OCNIdleState = TIM_OCNIdleState_Reset,
},
.channels = pios_tim_servoport_rcvrport_pins,
.num_channels = 6,
};
const struct pios_servo_cfg pios_servo_rcvr_cfg = {
.tim_oc_init = {
.TIM_OCMode = TIM_OCMode_PWM1,
.TIM_OutputState = TIM_OutputState_Enable,
.TIM_OutputNState = TIM_OutputNState_Disable,
.TIM_Pulse = PIOS_SERVOS_INITIAL_POSITION,
.TIM_OCPolarity = TIM_OCPolarity_High,
.TIM_OCNPolarity = TIM_OCPolarity_High,
.TIM_OCIdleState = TIM_OCIdleState_Reset,
.TIM_OCNIdleState = TIM_OCNIdleState_Reset,
},
.channels = pios_tim_servoport_rcvrport_pins,
.num_channels = NELEMENTS(pios_tim_servoport_rcvrport_pins),
};
#endif /* PIOS_INCLUDE_SERVO && PIOS_INCLUDE_TIM */
/*
* PPM Inputs
*/
#if defined(PIOS_INCLUDE_PPM)
#include <pios_ppm_priv.h>
const struct pios_ppm_cfg pios_ppm_cfg = {
.tim_ic_init = {
.TIM_ICPolarity = TIM_ICPolarity_Rising,
.TIM_ICSelection = TIM_ICSelection_DirectTI,
.TIM_ICPrescaler = TIM_ICPSC_DIV1,
.TIM_ICFilter = 0x0,
},
/* Use only the first channel for ppm */
.channels = &pios_tim_rcvrport_all_channels[0],
.num_channels = 1,
};
const struct pios_ppm_cfg pios_ppm_pin8_cfg = {
.tim_ic_init = {
.TIM_ICPolarity = TIM_ICPolarity_Rising,
.TIM_ICSelection = TIM_ICSelection_DirectTI,
.TIM_ICPrescaler = TIM_ICPSC_DIV1,
.TIM_ICFilter = 0x0,
},
/* Use only the first channel for ppm */
.channels = &pios_tim_rcvrport_all_channels[5],
.num_channels = 1,
};
#endif /* PIOS_INCLUDE_PPM */
#if defined(PIOS_INCLUDE_PPM_FLEXI)
#include <pios_ppm_priv.h>
const struct pios_ppm_cfg pios_ppm_flexi_cfg = {
.tim_ic_init = {
.TIM_ICPolarity = TIM_ICPolarity_Rising,
.TIM_ICSelection = TIM_ICSelection_DirectTI,
.TIM_ICPrescaler = TIM_ICPSC_DIV1,
.TIM_ICFilter = 0x0,
},
.channels = &pios_tim_ppm_flexi_port,
.num_channels = 1,
};
#endif /* PIOS_INCLUDE_PPM_FLEXI */
/*
* PWM Inputs
*/
#if defined(PIOS_INCLUDE_PWM)
#include <pios_pwm_priv.h>
const struct pios_pwm_cfg pios_pwm_cfg = {
.tim_ic_init = {
.TIM_ICPolarity = TIM_ICPolarity_Rising,
.TIM_ICSelection = TIM_ICSelection_DirectTI,
.TIM_ICPrescaler = TIM_ICPSC_DIV1,
.TIM_ICFilter = 0x0,
},
.channels = pios_tim_rcvrport_all_channels,
.num_channels = NELEMENTS(pios_tim_rcvrport_all_channels),
};
const struct pios_pwm_cfg pios_pwm_with_ppm_cfg = {
.tim_ic_init = {
.TIM_ICPolarity = TIM_ICPolarity_Rising,
.TIM_ICSelection = TIM_ICSelection_DirectTI,
.TIM_ICPrescaler = TIM_ICPSC_DIV1,
.TIM_ICFilter = 0x0,
},
/* Leave the first channel for PPM use and use the rest for PWM */
.channels = &pios_tim_rcvrport_all_channels[1],
.num_channels = NELEMENTS(pios_tim_rcvrport_all_channels) - 1,
};
#endif /* if defined(PIOS_INCLUDE_PWM) */
/*
* SONAR Inputs
*/
#if defined(PIOS_INCLUDE_HCSR04)
#include <pios_hcsr04_priv.h>
static const struct pios_tim_channel pios_tim_hcsr04_port_all_channels[] = {
{
.timer = TIM3,
.timer_chan = TIM_Channel_2,
.pin = {
.gpio = GPIOB,
.init = {
.GPIO_Pin = GPIO_Pin_5,
.GPIO_Mode = GPIO_Mode_IPD,
.GPIO_Speed = GPIO_Speed_2MHz,
},
},
.remap = GPIO_PartialRemap_TIM3,
},
};
const struct pios_hcsr04_cfg pios_hcsr04_cfg = {
.tim_ic_init = {
.TIM_ICPolarity = TIM_ICPolarity_Rising,
.TIM_ICSelection = TIM_ICSelection_DirectTI,
.TIM_ICPrescaler = TIM_ICPSC_DIV1,
.TIM_ICFilter = 0x0,
},
.channels = pios_tim_hcsr04_port_all_channels,
.num_channels = NELEMENTS(pios_tim_hcsr04_port_all_channels),
.trigger = {
.gpio = GPIOB,
.init = {
.GPIO_Pin = GPIO_Pin_6,
.GPIO_Mode = GPIO_Mode_Out_PP,
.GPIO_Speed = GPIO_Speed_2MHz,
},
},
};
#endif /* if defined(PIOS_INCLUDE_HCSR04) */
#if defined(PIOS_INCLUDE_I2C)
#include <pios_i2c_priv.h>
/*
* I2C Adapters
*/
void PIOS_I2C_flexi_adapter_ev_irq_handler(void);
void PIOS_I2C_flexi_adapter_er_irq_handler(void);
void I2C2_EV_EXTI24_IRQHandler() __attribute__((alias("PIOS_I2C_flexi_adapter_ev_irq_handler")));
void I2C2_ER_IRQHandler() __attribute__((alias("PIOS_I2C_flexi_adapter_er_irq_handler")));
static const struct pios_i2c_adapter_cfg pios_i2c_flexi_adapter_cfg = {
.regs = I2C2,
.init = {
.I2C_Mode = I2C_Mode_I2C,
.I2C_OwnAddress1 = 0,
.I2C_Ack = I2C_Ack_Enable,
.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit,
.I2C_DigitalFilter = 0x00,
.I2C_AnalogFilter = I2C_AnalogFilter_Enable,
.I2C_Timing = 0x70310309, // 50kHz I2C @ 8MHz input -> PRESC=0x7, SCLDEL=0x3, SDADEL=0x1, SCLH=0x03, SCLL=0x09
},
.remapSDA = GPIO_AF_4, /* I2C1, I2C2 */
.remapSCL = GPIO_AF_4, /* I2C1, I2C2 */
.transfer_timeout_ms = 50,
.scl = {
.gpio = GPIOB,
.init = {
.GPIO_Pin = GPIO_Pin_10,
.GPIO_Mode = GPIO_Mode_AF,
.GPIO_Speed = GPIO_Speed_50MHz,
.GPIO_OType = GPIO_OType_OD,
.GPIO_PuPd = GPIO_PuPd_UP,
},
},
.sda = {
.gpio = GPIOB,
.init = {
.GPIO_Pin = GPIO_Pin_11,
.GPIO_Mode = GPIO_Mode_AF,
.GPIO_Speed = GPIO_Speed_50MHz,
.GPIO_OType = GPIO_OType_OD,
.GPIO_PuPd = GPIO_PuPd_UP,
},
},
.event = {
.flags = 0, /* FIXME: check this */
.init = {
.NVIC_IRQChannel = I2C2_EV_IRQn,
.NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGHEST,
.NVIC_IRQChannelSubPriority = 0,
.NVIC_IRQChannelCmd = ENABLE,
},
},
.error = {
.flags = 0, /* FIXME: check this */
.init = {
.NVIC_IRQChannel = I2C2_ER_IRQn,
.NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGHEST,
.NVIC_IRQChannelSubPriority = 0,
.NVIC_IRQChannelCmd = ENABLE,
},
},
};
uint32_t pios_i2c_flexi_adapter_id;
void PIOS_I2C_flexi_adapter_ev_irq_handler(void)
{
/* Call into the generic code to handle the IRQ for this specific device */
PIOS_I2C_EV_IRQ_Handler(pios_i2c_flexi_adapter_id);
}
void PIOS_I2C_flexi_adapter_er_irq_handler(void)
{
/* Call into the generic code to handle the IRQ for this specific device */
PIOS_I2C_ER_IRQ_Handler(pios_i2c_flexi_adapter_id);
}
#endif /* PIOS_INCLUDE_I2C */
#if defined(PIOS_INCLUDE_RCVR)
#include "pios_rcvr_priv.h"
#endif /* PIOS_INCLUDE_RCVR */
#if defined(PIOS_INCLUDE_USB)
#include "pios_usb_priv.h"
static const struct pios_usb_cfg pios_usb_main_cfg_cc3d = {
.irq = {
.init = {
.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn,
.NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_LOW,
.NVIC_IRQChannelSubPriority = 0,
.NVIC_IRQChannelCmd = ENABLE,
},
},
.vsense = {
.gpio = GPIOC,
.init = {
.GPIO_Pin = GPIO_Pin_14,
.GPIO_Speed = GPIO_Speed_2MHz,
.GPIO_Mode = GPIO_Mode_IN,
.GPIO_OType = GPIO_OType_OD,
.GPIO_PuPd = GPIO_PuPd_DOWN,
},
},
.vsense_active_low = false
};
const struct pios_usb_cfg *PIOS_BOARD_HW_DEFS_GetUsbCfg(__attribute__((unused)) uint32_t board_revision)
{
return &pios_usb_main_cfg_cc3d;
}
#endif /* PIOS_INCLUDE_USB */
/**
* Configuration for MPU6000 chip
*/
#if defined(PIOS_INCLUDE_MPU6000)
#include "pios_mpu6000.h"
static const struct pios_exti_cfg pios_exti_mpu6000_cfg __exti_config = {
.vector = PIOS_MPU6000_IRQHandler,
.line = EXTI_Line3,
.pin = {
.gpio = GPIOA,
.init = {
.GPIO_Pin = GPIO_Pin_3,
.GPIO_Speed = GPIO_Speed_10MHz,
.GPIO_Mode = GPIO_Mode_IN,
.GPIO_OType = GPIO_OType_OD,
.GPIO_PuPd = GPIO_PuPd_NOPULL,
},
},
.irq = {
.init = {
.NVIC_IRQChannel = EXTI3_IRQn,
.NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGH,
.NVIC_IRQChannelSubPriority = 0,
.NVIC_IRQChannelCmd = ENABLE,
},
},
.exti = {
.init = {
.EXTI_Line = EXTI_Line3, // matches above GPIO pin
.EXTI_Mode = EXTI_Mode_Interrupt,
.EXTI_Trigger = EXTI_Trigger_Rising,
.EXTI_LineCmd = ENABLE,
},
},
};
static const struct pios_mpu6000_cfg pios_mpu6000_cfg = {
.exti_cfg = &pios_exti_mpu6000_cfg,
.Fifo_store = PIOS_MPU6000_FIFO_TEMP_OUT | PIOS_MPU6000_FIFO_GYRO_X_OUT | PIOS_MPU6000_FIFO_GYRO_Y_OUT | PIOS_MPU6000_FIFO_GYRO_Z_OUT,
// Clock at 8 khz, downsampled by 8 for 1000 Hz
.Smpl_rate_div_no_dlp = 7,
// Clock at 1 khz, downsampled by 1 for 1000 Hz
.Smpl_rate_div_dlp = 0,
.interrupt_cfg = PIOS_MPU6000_INT_CLR_ANYRD,
.interrupt_en = PIOS_MPU6000_INTEN_DATA_RDY,
.User_ctl = PIOS_MPU6000_USERCTL_DIS_I2C,
.Pwr_mgmt_clk = PIOS_MPU6000_PWRMGMT_PLL_X_CLK,
.accel_range = PIOS_MPU6000_ACCEL_8G,
.gyro_range = PIOS_MPU6000_SCALE_2000_DEG,
.filter = PIOS_MPU6000_LOWPASS_256_HZ,
.orientation = PIOS_MPU6000_TOP_180DEG,
.fast_prescaler = PIOS_SPI_PRESCALER_4,
.std_prescaler = PIOS_SPI_PRESCALER_64,
.max_downsample = 2
};
const struct pios_mpu6000_cfg *PIOS_BOARD_HW_DEFS_GetMPU6000Cfg(__attribute__((unused)) uint32_t board_revision)
{
return &pios_mpu6000_cfg;
}
#endif /* PIOS_INCLUDE_MPU6000 */

View File

@ -0,0 +1,29 @@
#
# Copyright (c) 2015, The LibrePilot Project, http://www.librepilot.org
# Copyright (c) 2009-2013, The OpenPilot Team, http://www.openpilot.org
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program 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 this program; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
ifndef FLIGHT_MAKEFILE
$(error Top level Makefile must be used to build this target)
endif
include ../board-info.mk
include $(FLIGHT_ROOT_DIR)/make/firmware-defs.mk
include $(FLIGHT_ROOT_DIR)/make/boot-defs.mk
include $(FLIGHT_ROOT_DIR)/make/common-defs.mk
$(info Making bootloader for CCF3D, board revision $(BOARD_REVISION))

Some files were not shown because too many files have changed in this diff Show More