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:
commit
0177a824d3
1
Makefile
1
Makefile
@ -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.
|
||||
|
@ -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)
|
||||
|
@ -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 */,
|
||||
|
@ -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)) \
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)))
|
||||
|
@ -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).
|
||||
|
@ -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)))
|
||||
|
||||
|
@ -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, $$@)
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
20
flight/pios/common/libraries/FreeRTOS/Source/openocd.c
Normal file
20
flight/pios/common/libraries/FreeRTOS/Source/openocd.c
Normal 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;
|
@ -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);
|
||||
}
|
||||
|
405
flight/pios/common/pios_bmp280.c
Normal file
405
flight/pios/common/pios_bmp280.c
Normal 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 */
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
*/
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
61
flight/pios/inc/pios_bmp280.h
Normal file
61
flight/pios/inc/pios_bmp280.h
Normal 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 */
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
*/
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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 */
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
39
flight/pios/stm32f30x/inc/pios_architecture.h
Normal file
39
flight/pios/stm32f30x/inc/pios_architecture.h
Normal 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 */
|
43
flight/pios/stm32f30x/inc/pios_delay_raw.h
Normal file
43
flight/pios/stm32f30x/inc/pios_delay_raw.h
Normal 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 */
|
53
flight/pios/stm32f30x/inc/pios_servo_config.h
Normal file
53
flight/pios/stm32f30x/inc/pios_servo_config.h
Normal 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_ */
|
61
flight/pios/stm32f30x/inc/pios_usart_config.h
Normal file
61
flight/pios/stm32f30x/inc/pios_usart_config.h
Normal 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_ */
|
78
flight/pios/stm32f30x/inc/pios_ws2811_cfg.h
Normal file
78
flight/pios/stm32f30x/inc/pios_ws2811_cfg.h
Normal 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_ */
|
82
flight/pios/stm32f30x/inc/stm32f30x_conf.h
Normal file
82
flight/pios/stm32f30x/inc/stm32f30x_conf.h
Normal 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>© 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****/
|
197
flight/pios/stm32f30x/inc/usb_conf.h
Normal file
197
flight/pios/stm32f30x/inc/usb_conf.h
Normal 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****/
|
63
flight/pios/stm32f30x/library.mk
Normal file
63
flight/pios/stm32f30x/library.mk
Normal 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
|
26
flight/pios/stm32f30x/link_memory.lds
Normal file
26
flight/pios/stm32f30x/link_memory.lds
Normal 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
|
||||
}
|
197
flight/pios/stm32f30x/link_sections.lds
Normal file
197
flight/pios/stm32f30x/link_sections.lds
Normal 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) }
|
||||
}
|
450
flight/pios/stm32f30x/pios_adc.c
Normal file
450
flight/pios/stm32f30x/pios_adc.c
Normal 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 */
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
*/
|
111
flight/pios/stm32f30x/pios_bkp.c
Normal file
111
flight/pios/stm32f30x/pios_bkp.c
Normal 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
|
||||
****************************************************************************************/
|
127
flight/pios/stm32f30x/pios_bl_helper.c
Normal file
127
flight/pios/stm32f30x/pios_bl_helper.c
Normal 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 */
|
178
flight/pios/stm32f30x/pios_debug.c
Normal file
178
flight/pios/stm32f30x/pios_debug.c
Normal 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) {
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
*/
|
184
flight/pios/stm32f30x/pios_delay.c
Normal file
184
flight/pios/stm32f30x/pios_delay.c
Normal 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 */
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
*/
|
326
flight/pios/stm32f30x/pios_exti.c
Normal file
326
flight/pios/stm32f30x/pios_exti.c
Normal 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 */
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
*/
|
304
flight/pios/stm32f30x/pios_flash_internal.c
Normal file
304
flight/pios/stm32f30x/pios_flash_internal.c
Normal 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,
|
||||
§or_number,
|
||||
§or_start,
|
||||
§or_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,
|
||||
§or_number,
|
||||
§or_start,
|
||||
§or_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,
|
||||
§or_number,
|
||||
§or_start,
|
||||
§or_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 */
|
170
flight/pios/stm32f30x/pios_gpio.c
Normal file
170
flight/pios/stm32f30x/pios_gpio.c
Normal 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 */
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
*/
|
921
flight/pios/stm32f30x/pios_i2c.c
Normal file
921
flight/pios/stm32f30x/pios_i2c.c
Normal 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) */
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
*/
|
97
flight/pios/stm32f30x/pios_irq.c
Normal file
97
flight/pios/stm32f30x/pios_irq.c
Normal 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 */
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
*/
|
401
flight/pios/stm32f30x/pios_ppm.c
Normal file
401
flight/pios/stm32f30x/pios_ppm.c
Normal 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 */
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
*/
|
283
flight/pios/stm32f30x/pios_pwm.c
Normal file
283
flight/pios/stm32f30x/pios_pwm.c
Normal 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 */
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
*/
|
141
flight/pios/stm32f30x/pios_rtc.c
Normal file
141
flight/pios/stm32f30x/pios_rtc.c
Normal 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 */
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
*/
|
751
flight/pios/stm32f30x/pios_spi.c
Normal file
751
flight/pios/stm32f30x/pios_spi.c
Normal 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 */
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
*/
|
287
flight/pios/stm32f30x/pios_sys.c
Normal file
287
flight/pios/stm32f30x/pios_sys.c
Normal 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) */
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
*/
|
401
flight/pios/stm32f30x/pios_tim.c
Normal file
401
flight/pios/stm32f30x/pios_tim.c
Normal 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 */
|
601
flight/pios/stm32f30x/pios_usart.c
Normal file
601
flight/pios/stm32f30x/pios_usart.c
Normal 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 */
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
*/
|
335
flight/pios/stm32f30x/pios_usb.c
Normal file
335
flight/pios/stm32f30x/pios_usb.c
Normal 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) */
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
*/
|
526
flight/pios/stm32f30x/pios_usb_cdc.c
Normal file
526
flight/pios/stm32f30x/pios_usb_cdc.c
Normal 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 */
|
380
flight/pios/stm32f30x/pios_usb_hid.c
Normal file
380
flight/pios/stm32f30x/pios_usb_hid.c
Normal 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 */
|
336
flight/pios/stm32f30x/pios_usb_hid_istr.c
Normal file
336
flight/pios/stm32f30x/pios_usb_hid_istr.c
Normal 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****/
|
292
flight/pios/stm32f30x/pios_usb_hid_pwr.c
Normal file
292
flight/pios/stm32f30x/pios_usb_hid_pwr.c
Normal 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****/
|
572
flight/pios/stm32f30x/pios_usbhook.c
Normal file
572
flight/pios/stm32f30x/pios_usbhook.c
Normal 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****/
|
186
flight/pios/stm32f30x/pios_wdg.c
Normal file
186
flight/pios/stm32f30x/pios_wdg.c
Normal 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 */
|
208
flight/pios/stm32f30x/pios_ws2811.c
Normal file
208
flight/pios/stm32f30x/pios_ws2811.c
Normal 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);
|
||||
}
|
189
flight/pios/stm32f30x/startup.c
Normal file
189
flight/pios/stm32f30x/startup.c
Normal 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,
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
370
flight/pios/stm32f30x/system.c
Normal file
370
flight/pios/stm32f30x/system.c
Normal 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>© 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****/
|
233
flight/pios/stm32f30x/vectors_stm32f30x.c
Normal file
233
flight/pios/stm32f30x/vectors_stm32f30x.c
Normal 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
|
||||
};
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
@ -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_ */
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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? */
|
||||
|
||||
|
@ -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 */
|
||||
}
|
||||
|
@ -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()
|
||||
|
19
flight/targets/boards/ccf3d/board-info.mk
Normal file
19
flight/targets/boards/ccf3d/board-info.mk
Normal 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
|
860
flight/targets/boards/ccf3d/board_hw_defs.c
Normal file
860
flight/targets/boards/ccf3d/board_hw_defs.c
Normal 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 */
|
29
flight/targets/boards/ccf3d/bootloader/Makefile
Normal file
29
flight/targets/boards/ccf3d/bootloader/Makefile
Normal 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
Loading…
x
Reference in New Issue
Block a user