From 0397537cf0f7f11af6c3ba00a35930b01886177a Mon Sep 17 00:00:00 2001 From: David Sidrane Date: Mon, 25 Jan 2016 14:58:54 -1000 Subject: [PATCH] Adding input capture driver --- src/drivers/drv_input_capture.h | 189 ++++++++++ src/drivers/stm32/CMakeLists.txt | 1 + src/drivers/stm32/drv_input_capture.c | 477 ++++++++++++++++++++++++++ src/drivers/stm32/drv_input_capture.h | 42 +++ src/drivers/stm32/drv_io_timer.h | 3 +- 5 files changed, 710 insertions(+), 2 deletions(-) create mode 100644 src/drivers/drv_input_capture.h create mode 100644 src/drivers/stm32/drv_input_capture.c create mode 100644 src/drivers/stm32/drv_input_capture.h diff --git a/src/drivers/drv_input_capture.h b/src/drivers/drv_input_capture.h new file mode 100644 index 0000000000..5a931dafa3 --- /dev/null +++ b/src/drivers/drv_input_capture.h @@ -0,0 +1,189 @@ +/**************************************************************************** + * + * Copyright (c) 2012-2016 PX4 Development Team. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name PX4 nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/** + * @file Input capture interface. + * + * Input capture interface utilizes the FMU_AUX_PINS to time stamp + * an edge. + */ + +#pragma once + +#include +#include +#include + +#include "drv_hrt.h" + +__BEGIN_DECLS + +/** + * Path for the default capture input device. + * + * + */ +#define INPUT_CAPTURE_BASE_DEVICE_PATH "/dev/capture" +#define INPUT_CAPTURE0_DEVICE_PATH "/dev/capture0" + +typedef void (*capture_callback_t)(void *context, uint32_t chan_index, + hrt_abstime edge_time, uint32_t edge_state, uint32_t overflow); + +/** + * Maximum number of PWM output channels supported by the device. + */ +#ifndef INPUT_CAPTURE_MAX_CHANNELS +#define INPUT_CAPTURE_MAX_CHANNELS 6 +#endif + +typedef uint16_t capture_filter_t; +typedef uint16_t capture_t; + +typedef enum input_capture_edge { + Disabled = 0, + Rising = 1, + Falling = 2, + Both = 3 +} input_capture_edge; + +typedef struct input_capture_element_t { + hrt_abstime time_stamp; + input_capture_edge edge; + bool overrun; +} input_capture_element_t; + +typedef struct input_capture_stats_t { + uint32_t chan_in_edges_out; + uint32_t overflows; + uint32_t last_edge; + hrt_abstime last_time; + uint16_t latnecy; +} input_capture_stats_t; + +/** + * input capture values for a channel + * + * This allows for Capture input driver values to be set without a + * param_get() dependency + */ +typedef struct input_capture_config_t { + uint8_t channel; + capture_filter_t filter; + input_capture_edge edge; + capture_callback_t callback; + void *context; + +} input_capture_config_t; + +/* + * ioctl() definitions + * + * Note that ioctls and ORB updates should not be mixed, as the + * behaviour of the system in this case is not defined. + */ +#define _INPUT_CAP_BASE 0x2d00 + +/** Set Enable a channel arg is pointer to input_capture_config + * with all parameters set. + * edge controls the mode: Disable will free the capture channel. + * (When edge is Disabled call back and context are ignored) + * context may be null. If callback and context are null the + * callback will be disabled. + * */ + +#define INPUT_CAP_SET _PX4_IOC(_INPUT_CAP_BASE, 0) + +/** Set the call back on a capture channel - arg is pointer to + * input_capture_config with channel call back and context set + * context may be null. If both ate null the call back will be + * disabled */ +#define INPUT_CAP_SET_CALLBACK _PX4_IOC(_INPUT_CAP_BASE, 1) + +/** Get the call back on a capture channel - arg is pointer to + * input_capture_config with channel set. + */ +#define INPUT_CAP_GET_CALLBACK _PX4_IOC(_INPUT_CAP_BASE, 2) + +/** Set Edge a channel arg is pointer to input_capture_config + * with channel and edge set */ +#define INPUT_CAP_SET_EDGE _PX4_IOC(_INPUT_CAP_BASE, 3) + +/** Get Edge for a channel arg is pointer to input_capture_config + * with channel set */ +#define INPUT_CAP_GET_EDGE _PX4_IOC(_INPUT_CAP_BASE, 4) + +/** Set Filter input filter channel arg is pointer to input_capture_config + * with channel and filter set */ +#define INPUT_CAP_SET_FILTER _PX4_IOC(_INPUT_CAP_BASE, 5) + +/** Set Filter input filter channel arg is pointer to input_capture_config + * with channel set */ +#define INPUT_CAP_GET_FILTER _PX4_IOC(_INPUT_CAP_BASE, 6) + +/** Get the number of capture in *(unsigned *)arg */ +#define INPUT_CAP_GET_COUNT _PX4_IOC(_INPUT_CAP_BASE, 7) + +/** Set the number of capture in (unsigned)arg - allows change of + * split between servos and capture */ +#define INPUT_CAP_SET_COUNT _PX4_IOC(_INPUT_CAP_BASE, 8) + +/** Get channel stats - arg is pointer to input_capture_config + * with channel set. + */ +#define INPUT_CAP_GET_STATS _PX4_IOC(_INPUT_CAP_BASE, 9) + +/** Get channel stats - arg is pointer to input_capture_config + * with channel set. + */ +#define INPUT_CAP_GET_CLR_STATS _PX4_IOC(_INPUT_CAP_BASE, 10) + +/* + * + * + * WARNING WARNING WARNING! DO NOT EXCEED 31 IN IOC INDICES HERE! + * + * + */ + +__EXPORT int up_input_capture_set(unsigned channel, input_capture_edge edge, capture_filter_t filter, + capture_callback_t callback, void *context); + +__EXPORT int up_input_capture_get_filter(unsigned channel, capture_filter_t *filter); +__EXPORT int up_input_capture_set_filter(unsigned channel, capture_filter_t filter); + +__EXPORT int up_input_capture_get_trigger(unsigned channel, input_capture_edge *edge); +__EXPORT int up_input_capture_set_trigger(unsigned channel, input_capture_edge edge); +__EXPORT int up_input_capture_get_callback(unsigned channel, capture_callback_t *callback, void **context); +__EXPORT int up_input_capture_set_callback(unsigned channel, capture_callback_t callback, void *context); +__EXPORT int up_input_capture_get_stats(unsigned channel, input_capture_stats_t *stats, bool clear); +__END_DECLS diff --git a/src/drivers/stm32/CMakeLists.txt b/src/drivers/stm32/CMakeLists.txt index 35bafe2f36..b7b3825aa8 100644 --- a/src/drivers/stm32/CMakeLists.txt +++ b/src/drivers/stm32/CMakeLists.txt @@ -38,6 +38,7 @@ px4_add_module( drv_hrt.c drv_io_timer.c drv_pwm_servo.c + drv_input_capture.c DEPENDS platforms__common ) diff --git a/src/drivers/stm32/drv_input_capture.c b/src/drivers/stm32/drv_input_capture.c new file mode 100644 index 0000000000..c3da341049 --- /dev/null +++ b/src/drivers/stm32/drv_input_capture.c @@ -0,0 +1,477 @@ +/**************************************************************************** + * + * Copyright (C) 2012-2016 PX4 Development Team. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name PX4 nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/* + * @file drv_input_capture.c + * + * Servo driver supporting input capture connected to STM32 timer blocks. + * + * Works with any of the 'generic' or 'advanced' STM32 timers that + * have input pins. + * + * Require an interrupt. + * + * The use of thie interface is mutually exclusive with the pwm + * because the same timers are used and there is a resource contention + * with the ARR as it sets the pwm rate and in this driver needs to match + * that of the hrt to back calculate the actual point in time the edge + * was detected. + * + * This is accomplished by taking the difference between the current + * count rCNT snapped at the time interrupt and the rCCRx captured on the + * edge transition. This delta is applied to hrt time and the resulting + * value is the absolute system time the edge occured. + * + * + */ + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "drv_io_timer.h" + +#include "drv_input_capture.h" + +#include +#include +#include + +#include +#include +#include + +#define _REG32(_base, _reg) (*(volatile uint32_t *)(_base + _reg)) +#define REG(_tmr, _reg) _REG32(io_timers[_tmr].base, _reg) + +#define rCCMR1(_tmr) REG(_tmr, STM32_GTIM_CCMR1_OFFSET) +#define rCCMR2(_tmr) REG(_tmr, STM32_GTIM_CCMR2_OFFSET) +#define rCCER(_tmr) REG(_tmr, STM32_GTIM_CCER_OFFSET) + +#define GTIM_SR_CCOF (GTIM_SR_CC4OF|GTIM_SR_CC3OF|GTIM_SR_CC2OF|GTIM_SR_CC1OF) + +static input_capture_stats_t channel_stats[MAX_TIMER_IO_CHANNELS]; + +static struct channel_handler_entry { + capture_callback_t callback; + void *context; +} channel_handlers[MAX_TIMER_IO_CHANNELS]; + + + +static void input_capture_chan_handler(void *context, const io_timers_t *timer, uint32_t chan_index, + const timer_io_channels_t *chan, + hrt_abstime isrs_time , uint16_t isrs_rcnt) +{ + uint16_t capture = _REG32(timer, chan->ccr_offset); + channel_stats[chan_index].last_edge = stm32_gpioread(chan->gpio_in); + + if ((isrs_rcnt - capture) > channel_stats[chan_index].latnecy) { + channel_stats[chan_index].latnecy = (isrs_rcnt - capture); + } + + channel_stats[chan_index].chan_in_edges_out++; + channel_stats[chan_index].last_time = isrs_time - (isrs_rcnt - capture); + uint32_t overflow = _REG32(timer, STM32_GTIM_SR_OFFSET) & chan->masks & GTIM_SR_CCOF; + + if (overflow) { + + /* Error we has a second edge before we cleared CCxR */ + + channel_stats[chan_index].overflows++; + } + + if (channel_handlers[chan_index].callback) { + channel_handlers[chan_index].callback(channel_handlers[chan_index].context, chan_index, + channel_stats[chan_index].last_time, + channel_stats[chan_index].last_edge, overflow); + } +} + +static void input_capture_bind(unsigned channel, capture_callback_t callback, void *context) +{ + irqstate_t flags = irqsave(); + channel_handlers[channel].callback = callback; + channel_handlers[channel].context = context; + irqrestore(flags); +} + +static void input_capture_unbind(unsigned channel) +{ + input_capture_bind(channel, NULL, NULL); +} + +int up_input_capture_set(unsigned channel, input_capture_edge edge, capture_filter_t filter, + capture_callback_t callback, void *context) +{ + if (filter > GTIM_CCMR1_IC1F_MASK) { + return -EINVAL; + } + + if (edge > Both) { + return -EINVAL; + } + int rv = io_timer_validate_channel_index(channel); + if (rv == 0) { + if (edge == Disabled) { + + io_timer_set_enable(false, IOTimerChanMode_Capture, 1 << channel); + input_capture_unbind(channel); + + } else { + + if (-EBUSY == io_timer_is_channel_free(channel)) { + io_timer_free_channel(channel); + } + + input_capture_bind(channel, callback, context); + + int rv = io_timer_channel_init(channel, IOTimerChanMode_Capture, input_capture_chan_handler, context); + + if (rv != 0) { + return rv; + } + + rv = up_input_capture_set_filter(channel, filter); + if (rv == 0) { + rv = up_input_capture_set_trigger(channel, edge); + if (rv == 0) { + rv = io_timer_set_enable(true, IOTimerChanMode_Capture, 1 << channel); + } + } + } + } + return rv; +} + +int up_input_capture_get_filter(unsigned channel, capture_filter_t *filter) +{ + int rv = io_timer_validate_channel_index(channel); + if (rv == 0) { + + rv = -ENXIO; + + /* Any pins in capture mode */ + + if (io_timer_get_channel_mode(channel) == IOTimerChanMode_Capture) { + + uint32_t timer = timer_io_channels[channel].timer_index; + uint16_t rvalue; + rv = OK; + switch (timer_io_channels[channel].timer_channel) { + + case 1: + rvalue = rCCMR1(timer) & GTIM_CCMR1_IC1F_MASK; + *filter = (rvalue << GTIM_CCMR1_IC1F_SHIFT); + break; + + case 2: + rvalue = rCCMR1(timer) & GTIM_CCMR1_IC2F_MASK; + *filter = (rvalue << GTIM_CCMR1_IC2F_SHIFT); + break; + + case 3: + rvalue = rCCMR2(timer) & GTIM_CCMR2_IC3F_MASK; + *filter = (rvalue << GTIM_CCMR2_IC3F_SHIFT); + break; + + case 4: + rvalue = rCCMR2(timer) & GTIM_CCMR2_IC4F_MASK; + *filter = (rvalue << GTIM_CCMR2_IC4F_SHIFT); + break; + + default: + rv = -EIO; + } + } + } + return rv; +} +int up_input_capture_set_filter(unsigned channel, capture_filter_t filter) +{ + if (filter > GTIM_CCMR1_IC1F_MASK) { + return -EINVAL; + } + + int rv = io_timer_validate_channel_index(channel); + if (rv == 0) { + + rv = -ENXIO; + + /* Any pins in capture mode */ + + if (io_timer_get_channel_mode(channel) == IOTimerChanMode_Capture) { + + rv = OK; + uint32_t timer = timer_io_channels[channel].timer_index; + uint16_t rvalue; + + irqstate_t flags = irqsave(); + + switch (timer_io_channels[channel].timer_channel) { + + case 1: + rvalue = rCCMR1(timer) & ~GTIM_CCMR1_IC1F_MASK; + rvalue |= (filter << GTIM_CCMR1_IC1F_SHIFT); + rCCMR1(timer) = rvalue; + break; + + case 2: + rvalue = rCCMR1(timer) & ~GTIM_CCMR1_IC2F_MASK; + rvalue |= (filter << GTIM_CCMR1_IC2F_SHIFT); + rCCMR1(timer) = rvalue; + break; + + case 3: + rvalue = rCCMR2(timer) & ~GTIM_CCMR2_IC3F_MASK; + rvalue |= (filter << GTIM_CCMR2_IC3F_SHIFT); + rCCMR2(timer) = rvalue; + break; + + case 4: + rvalue = rCCMR2(timer) & ~GTIM_CCMR2_IC4F_MASK; + rvalue |= (filter << GTIM_CCMR2_IC4F_SHIFT); + rCCMR1(timer) = rvalue; + break; + + default: + rv = -EIO; + } + irqrestore(flags); + } + } + return rv; +} + +int up_input_capture_get_trigger(unsigned channel, input_capture_edge *edge) +{ + int rv = io_timer_validate_channel_index(channel); + if (rv == 0) { + + rv = -ENXIO; + + /* Any pins in capture mode */ + + if (io_timer_get_channel_mode(channel) == IOTimerChanMode_Capture) { + + rv = OK; + + uint32_t timer = timer_io_channels[channel].timer_index; + uint16_t rvalue; + switch (timer_io_channels[channel].timer_channel) { + + case 1: + rvalue = rCCER(timer) & (GTIM_CCER_CC1P | GTIM_CCER_CC1NP); + break; + + case 2: + rvalue = rCCER(timer) & (GTIM_CCER_CC2P | GTIM_CCER_CC2NP); + rvalue >>= 4; + break; + + case 3: + rvalue = rCCER(timer) & (GTIM_CCER_CC3P | GTIM_CCER_CC3NP); + rvalue >>= 8; + break; + + case 4: + rvalue = rCCER(timer) & (GTIM_CCER_CC4P | GTIM_CCER_CC4NP); + rvalue >>= 12; + break; + + default: + rv = -EIO; + } + if (rv == 0) { + switch(rvalue) { + + case 0: + *edge = Rising; + break; + case (GTIM_CCER_CC1P | GTIM_CCER_CC1NP): + *edge = Both; + break; + case (GTIM_CCER_CC1P): + *edge = Falling; + break; + default: + rv = -EIO; + } + } + } + } + return rv; +} +int up_input_capture_set_trigger(unsigned channel, input_capture_edge edge) +{ + int rv = io_timer_validate_channel_index(channel); + if (rv == 0) { + + rv = -ENXIO; + + /* Any pins in capture mode */ + + if (io_timer_get_channel_mode(channel) == IOTimerChanMode_Capture) { + + uint16_t edge_bits = 0xffff; + + switch (edge) { + case Disabled: + break; + + case Rising: + edge_bits = 0; + break; + + case Falling: + edge_bits = GTIM_CCER_CC1P; + break; + + case Both: + edge_bits = GTIM_CCER_CC1P | GTIM_CCER_CC1NP; + break; + + default: + return -EINVAL;; + } + + uint32_t timer = timer_io_channels[channel].timer_index; + uint16_t rvalue; + rv = OK; + + irqstate_t flags = irqsave(); + + switch (timer_io_channels[channel].timer_channel) { + + case 1: + rvalue = rCCER(timer); + rvalue &= ~(GTIM_CCER_CC1P | GTIM_CCER_CC1NP); + rvalue |= edge_bits; + rCCER(timer) = rvalue; + break; + + case 2: + rvalue = rCCER(timer); + rvalue &= ~(GTIM_CCER_CC2P | GTIM_CCER_CC2NP); + rvalue |= (edge_bits << 4); + rCCER(timer) = rvalue; + break; + + case 3: + rvalue = rCCER(timer); + rvalue &= ~(GTIM_CCER_CC3P | GTIM_CCER_CC3NP); + rvalue |= edge_bits << 8; + rCCER(timer) = rvalue; + break; + + case 4: + rvalue = rCCER(timer); + rvalue &= ~(GTIM_CCER_CC4P | GTIM_CCER_CC4NP); + rvalue |= edge_bits << 12; + rCCER(timer) = rvalue; + break; + + default: + rv = -EIO; + } + irqrestore(flags); + } + } + return rv; +} + +int up_input_capture_get_callback(unsigned channel, capture_callback_t *callback, void **context) +{ + int rv = io_timer_validate_channel_index(channel); + if (rv == 0) { + + rv = -ENXIO; + + /* Any pins in capture mode */ + + if (io_timer_get_channel_mode(channel) == IOTimerChanMode_Capture) { + + irqstate_t flags = irqsave(); + *callback = channel_handlers[channel].callback; + *context = channel_handlers[channel].context; + irqrestore(flags); + rv = OK; + } + } + return rv; + +} + +int up_input_capture_set_callback(unsigned channel, capture_callback_t callback, void *context) +{ + int rv = io_timer_validate_channel_index(channel); + if (rv == 0) { + + rv = -ENXIO; + + /* Any pins in capture mode */ + + if (io_timer_get_channel_mode(channel) == IOTimerChanMode_Capture) { + input_capture_bind(channel, callback, context); + rv = 0; + } + } + return rv; +} + +int up_input_capture_get_stats(unsigned channel, input_capture_stats_t *stats, bool clear) +{ + int rv = io_timer_validate_channel_index(channel); + if (rv == 0) { + irqstate_t flags = irqsave(); + *stats = channel_stats[channel]; + if (clear) { + memset(&channel_stats[channel], 0, sizeof(*stats)); + } + irqrestore(flags); + } + return rv; +} diff --git a/src/drivers/stm32/drv_input_capture.h b/src/drivers/stm32/drv_input_capture.h new file mode 100644 index 0000000000..968ce831ef --- /dev/null +++ b/src/drivers/stm32/drv_input_capture.h @@ -0,0 +1,42 @@ +/**************************************************************************** + * + * Copyright (C) 2012-2016 PX4 Development Team. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name PX4 nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/** + * @file drv_input_capture.h + * + * stm32-specific input capture data. + */ + +#pragma once + +#include diff --git a/src/drivers/stm32/drv_io_timer.h b/src/drivers/stm32/drv_io_timer.h index ded546e556..0cd59a4e1e 100644 --- a/src/drivers/stm32/drv_io_timer.h +++ b/src/drivers/stm32/drv_io_timer.h @@ -43,7 +43,7 @@ #include #pragma once - +__BEGIN_DECLS /* configuration limits */ #define MAX_IO_TIMERS 4 #define MAX_TIMER_IO_CHANNELS 8 @@ -110,5 +110,4 @@ __EXPORT int io_timer_is_channel_free(unsigned channel); __EXPORT int io_timer_free_channel(unsigned channel); __EXPORT int io_timer_get_channel_mode(unsigned channel); __EXPORT int io_timer_get_mode_channels(io_timer_channel_mode_t mode); - __END_DECLS