diff --git a/src/drivers/boards/nxphlite-v3/CMakeLists.txt b/src/drivers/boards/nxphlite-v3/CMakeLists.txt index b53d8cd436..e05e1d782b 100644 --- a/src/drivers/boards/nxphlite-v3/CMakeLists.txt +++ b/src/drivers/boards/nxphlite-v3/CMakeLists.txt @@ -44,7 +44,6 @@ px4_add_module( nxphlite_can.c nxphlite_init.c nxphlite_led.c - nxphlite_pwm.c nxphlite_sdhc.c nxphlite_spi.c nxphlite_timer_config.c diff --git a/src/drivers/boards/nxphlite-v3/nxphlite_pwm.c b/src/drivers/boards/nxphlite-v3/nxphlite_pwm.c deleted file mode 100644 index 25e3908ef9..0000000000 --- a/src/drivers/boards/nxphlite-v3/nxphlite_pwm.c +++ /dev/null @@ -1,106 +0,0 @@ -/************************************************************************************ - * - * Copyright (C) 2013, 2015, 2016 Gregory Nutt. All rights reserved. - * Authors: Gregory Nutt - * Jordan MacIntyre - * David Sidrane - * - * 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 NuttX 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. - * - ************************************************************************************/ - -/************************************************************************************ - * Included Files - ************************************************************************************/ - -#include - -#include -#include -#include - -#include -#include - -#include - -#include "chip.h" -#include "up_arch.h" -#include "kinetis_pwm.h" - -#ifdef CONFIG_PWM - -/************************************************************************************ - * Public Functions - ************************************************************************************/ - -/************************************************************************************ - * Name: board_pwm_setup - * - * Description: - * All Kinetis K architectures must provide the following interface to work with - * examples/pwm. - * - ************************************************************************************/ - -int board_pwm_setup(void) -{ - FAR struct pwm_lowerhalf_s *pwm; - static bool initialized = false; - int ret; - - /* Have we already initialized? */ - - if (!initialized) { - /* Call nxphlite_pwminitialize() to get an instance of the PWM interface */ - - pwm = kinetis_pwminitialize(0); - - if (!pwm) { - aerr("ERROR: Failed to get the kinetis PWM lower half\n"); - return -ENODEV; - } - - /* Register the PWM driver at "/dev/pwm0" */ - - ret = pwm_register("/dev/pwm0", pwm); - - if (ret < 0) { - aerr("ERROR: pwm_register failed: %d\n", ret); - return ret; - } - - /* Now we are initialized */ - - initialized = true; - } - - return OK; -} - -#endif /* CONFIG_PWM */ diff --git a/src/drivers/kinetis/drv_input_capture.c b/src/drivers/kinetis/drv_input_capture.c index 4a229fa238..c44138118d 100644 --- a/src/drivers/kinetis/drv_input_capture.c +++ b/src/drivers/kinetis/drv_input_capture.c @@ -77,31 +77,18 @@ #include "drv_input_capture.h" #include -//#include -#define GTIM_CCMR1_IC1F_MASK 0 -static volatile uint32_t dummy[4]; -#define __REG32(_reg) (*(volatile uint32_t *)(&dummy[(_reg)])) -#define STM32_GTIM_SR_OFFSET 0 -#define GTIM_CCMR1_IC1F_SHIFT 0 -#define GTIM_CCMR1_IC2F_MASK 0 -#define GTIM_CCMR1_IC2F_SHIFT 0 -#define GTIM_CCMR1_IC3F_SHIFT 0 -#define GTIM_CCMR1_IC3F_MASK 0 -#define GTIM_CCMR2_IC3F_MASK 0 -#define GTIM_CCMR2_IC3F_SHIFT 0 -#define GTIM_CCMR2_IC4F_MASK 0 -#define GTIM_CCMR2_IC4F_SHIFT 0 -#define GTIM_CCER_CC1P 12 -#define GTIM_CCER_CC1NP 14 +#include "chip/kinetis_sim.h" +#include "chip/kinetis_ftm.h" -#define _REG32(_base, _reg) __REG32(_reg) + +#define _REG(_addr) (*(volatile uint32_t *)(_addr)) +#define _REG32(_base, _reg) (*(volatile uint32_t *)(_base + _reg)) #define REG(_tmr, _reg) _REG32(io_timers[_tmr].base, _reg) -#define rCCMR1(_tmr) REG(_tmr, 0) -#define rCCMR2(_tmr) REG(_tmr, 1) -#define rCCER(_tmr) REG(_tmr, 2) -#define GTIM_SR_CCOF 0 //(GTIM_SR_CC4OF|GTIM_SR_CC3OF|GTIM_SR_CC2OF|GTIM_SR_CC1OF) +/* Timer register accessors */ + +#define rFILTER(_tmr) REG(_tmr,KINETIS_FTM_FILTER_OFFSET) static input_capture_stats_t channel_stats[MAX_TIMER_IO_CHANNELS]; @@ -114,9 +101,9 @@ static struct channel_handler_entry { 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) + hrt_abstime isrs_time, uint16_t isrs_rcnt, + uint16_t capture) { - uint16_t capture = _REG32(timer, chan->ccr_offset); channel_stats[chan_index].last_edge = px4_arch_gpioread(chan->gpio_in); if ((isrs_rcnt - capture) > channel_stats[chan_index].latnecy) { @@ -125,7 +112,7 @@ static void input_capture_chan_handler(void *context, const io_timers_t *timer, 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; + uint32_t overflow = _REG32(timer, KINETIS_FTM_CSC_OFFSET(chan->timer_channel - 1)) & FTM_CSC_CHF; if (overflow) { @@ -157,7 +144,7 @@ static void input_capture_unbind(unsigned channel) 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) { + if (filter > FTM_FILTER_CH0FVAL_MASK) { return -EINVAL; } @@ -168,6 +155,15 @@ int up_input_capture_set(unsigned channel, input_capture_edge edge, capture_filt int rv = io_timer_validate_channel_index(channel); if (rv == 0) { + + /* This register selects the filter value for the inputs of channels. + Channels 4, 5, 6 and 7 do not have an input filter. + */ + if (filter && timer_io_channels[channel].timer_channel - 1 > 3) { + return -EINVAL; + } + + if (edge == Disabled) { io_timer_set_enable(false, IOTimerChanMode_Capture, 1 << channel); @@ -208,41 +204,44 @@ int up_input_capture_get_filter(unsigned channel, capture_filter_t *filter) if (rv == 0) { - rv = -ENXIO; + rv = -EINVAL; - /* Any pins in capture mode */ + if (timer_io_channels[channel].timer_channel - 1 <= 3) { + rv = -ENXIO; - if (io_timer_get_channel_mode(channel) == IOTimerChanMode_Capture) { + /* Any pins in capture mode */ - uint32_t timer = timer_io_channels[channel].timer_index; - (void) timer; - uint16_t rvalue; - rv = OK; + if (io_timer_get_channel_mode(channel) == IOTimerChanMode_Capture) { - switch (timer_io_channels[channel].timer_channel) { + uint32_t timer = timer_io_channels[channel].timer_index; + uint16_t rvalue; + rv = OK; - case 1: - rvalue = rCCMR1(timer) & GTIM_CCMR1_IC1F_MASK; - *filter = (rvalue << GTIM_CCMR1_IC1F_SHIFT); - break; + switch (timer_io_channels[channel].timer_channel) { - case 2: - rvalue = rCCMR1(timer) & GTIM_CCMR1_IC2F_MASK; - *filter = (rvalue << GTIM_CCMR1_IC2F_SHIFT); - break; + case 1: + rvalue = rFILTER(timer) & FTM_FILTER_CH0FVAL_MASK; + *filter = (rvalue >> FTM_FILTER_CH0FVAL_SHIFT); + break; - case 3: - rvalue = rCCMR2(timer) & GTIM_CCMR2_IC3F_MASK; - *filter = (rvalue << GTIM_CCMR2_IC3F_SHIFT); - break; + case 2: + rvalue = rFILTER(timer) & FTM_FILTER_CH1FVAL_MASK; + *filter = (rvalue >> FTM_FILTER_CH1FVAL_SHIFT); + break; - case 4: - rvalue = rCCMR2(timer) & GTIM_CCMR2_IC4F_MASK; - *filter = (rvalue << GTIM_CCMR2_IC4F_SHIFT); - break; + case 3: + rvalue = rFILTER(timer) & FTM_FILTER_CH2FVAL_MASK; + *filter = (rvalue >> FTM_FILTER_CH2FVAL_SHIFT); + break; - default: - rv = -EIO; + case 4: + rvalue = rFILTER(timer) & FTM_FILTER_CH3FVAL_MASK; + *filter = (rvalue >> FTM_FILTER_CH3FVAL_SHIFT); + break; + + default: + rv = -EIO; + } } } } @@ -251,7 +250,7 @@ int up_input_capture_get_filter(unsigned channel, capture_filter_t *filter) } int up_input_capture_set_filter(unsigned channel, capture_filter_t filter) { - if (filter > GTIM_CCMR1_IC1F_MASK) { + if (filter > FTM_FILTER_CH0FVAL_MASK) { return -EINVAL; } @@ -266,7 +265,7 @@ int up_input_capture_set_filter(unsigned channel, capture_filter_t filter) if (io_timer_get_channel_mode(channel) == IOTimerChanMode_Capture) { rv = OK; -// uint32_t timer = timer_io_channels[channel].timer_index; + uint32_t timer = timer_io_channels[channel].timer_index; uint16_t rvalue; irqstate_t flags = px4_enter_critical_section(); @@ -274,27 +273,27 @@ int up_input_capture_set_filter(unsigned channel, capture_filter_t filter) 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; + rvalue = rFILTER(timer) & ~FTM_FILTER_CH0FVAL_MASK; + rvalue |= (filter << FTM_FILTER_CH0FVAL_SHIFT); + rFILTER(timer) = rvalue; break; case 2: - rvalue = rCCMR1(timer) & ~GTIM_CCMR1_IC2F_MASK; - rvalue |= (filter << GTIM_CCMR1_IC2F_SHIFT); - rCCMR1(timer) = rvalue; + rvalue = rFILTER(timer) & ~FTM_FILTER_CH1FVAL_MASK; + rvalue |= (filter << FTM_FILTER_CH1FVAL_SHIFT); + rFILTER(timer) = rvalue; break; case 3: - rvalue = rCCMR2(timer) & ~GTIM_CCMR2_IC3F_MASK; - rvalue |= (filter << GTIM_CCMR2_IC3F_SHIFT); - rCCMR2(timer) = rvalue; + rvalue = rFILTER(timer) & ~FTM_FILTER_CH2FVAL_MASK; + rvalue |= (filter << FTM_FILTER_CH2FVAL_SHIFT); + rFILTER(timer) = rvalue; break; case 4: - rvalue = rCCMR2(timer) & ~GTIM_CCMR2_IC4F_MASK; - rvalue |= (filter << GTIM_CCMR2_IC4F_SHIFT); - rCCMR1(timer) = rvalue; + rvalue = rFILTER(timer) & ~FTM_FILTER_CH2FVAL_MASK; + rvalue |= (filter << FTM_FILTER_CH2FVAL_SHIFT); + rFILTER(timer) = rvalue; break; default: @@ -322,53 +321,27 @@ int up_input_capture_get_trigger(unsigned channel, input_capture_edge *edge) rv = OK; -// uint32_t timer = timer_io_channels[channel].timer_index; - uint16_t rvalue; + uint32_t timer = timer_io_channels[channel].timer_index; + uint16_t rvalue = _REG32(timer, KINETIS_FTM_CSC_OFFSET(timer_io_channels[channel].timer_channel - 1)); + rvalue &= (FTM_CSC_MSB | FTM_CSC_MSA); - switch (timer_io_channels[channel].timer_channel) { + switch (rvalue) { - case 1: - rvalue = rCCER(timer) ;//& (GTIM_CCER_CC1P | GTIM_CCER_CC1NP); + case (FTM_CSC_MSA): + *edge = Rising; break; - case 2: - rvalue = rCCER(timer) ;//& (GTIM_CCER_CC2P | GTIM_CCER_CC2NP); - rvalue >>= 4; + case (FTM_CSC_MSB): + *edge = Falling; 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; + case (FTM_CSC_MSB|FTM_CSC_MSA): + *edge = Both; 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; - } - } } } @@ -386,69 +359,36 @@ int up_input_capture_set_trigger(unsigned channel, input_capture_edge edge) if (io_timer_get_channel_mode(channel) == IOTimerChanMode_Capture) { - uint16_t edge_bits = 0xffff; + uint16_t edge_bits = 0; switch (edge) { case Disabled: break; case Rising: - edge_bits = 0; + edge_bits = FTM_CSC_MSA; break; case Falling: - edge_bits = GTIM_CCER_CC1P; + edge_bits = FTM_CSC_MSB; break; case Both: - edge_bits = GTIM_CCER_CC1P | GTIM_CCER_CC1NP; + edge_bits = (FTM_CSC_MSB | FTM_CSC_MSA); break; default: return -EINVAL;; } - //uint32_t timer = timer_io_channels[channel].timer_index; - uint16_t rvalue; - rv = OK; - + uint32_t timer = timer_io_channels[channel].timer_index; irqstate_t flags = px4_enter_critical_section(); - - 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; - } - + uint32_t rvalue = _REG32(timer, KINETIS_FTM_CSC_OFFSET(timer_io_channels[channel].timer_channel - 1)); + rvalue &= (FTM_CSC_MSB | FTM_CSC_MSA); + rvalue |= edge_bits; + _REG32(timer, KINETIS_FTM_CSC_OFFSET(timer_io_channels[channel].timer_channel - 1)) = rvalue; px4_leave_critical_section(flags); + rv = OK; } } diff --git a/src/drivers/kinetis/drv_io_timer.c b/src/drivers/kinetis/drv_io_timer.c index eca0fc82e6..7d52199af1 100644 --- a/src/drivers/kinetis/drv_io_timer.c +++ b/src/drivers/kinetis/drv_io_timer.c @@ -1,6 +1,6 @@ /**************************************************************************** * - * Copyright (C) 2012 PX4 Development Team. All rights reserved. + * Copyright (C) 2017 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 @@ -32,15 +32,13 @@ ****************************************************************************/ /* - * @file drv_pwm_servo.c + * @file drv_io_timer.c * - * Servo driver supporting PWM servos connected to STM32 timer blocks. - * - * Works with any of the 'generic' or 'advanced' STM32 timers that - * have output pins, does not require an interrupt. + * Servo driver supporting PWM servos connected to Kinetis FTM timer blocks. */ #include +#include #include #include @@ -61,102 +59,91 @@ #include "drv_io_timer.h" #include -//#include +#include "chip/kinetis_sim.h" +#include "chip/kinetis_ftm.h" -#define arraySize(a) (sizeof((a))/sizeof(((a)[0]))) - -/* If the timer clock source provided as clock_freq is the STM32_APBx_TIMx_CLKIN - * then configure the timer to free-run at 1MHz. - * Otherwise, other frequencies are attainable by adjusting .clock_freq accordingly. - * For instance .clock_freq = 1000000 would set the prescaler to 1. - * We also allow for overrides here but all timer register usage need to be - * taken into account +/* The FTM prescalers are limited to Divide by 2^n where n={1-7} + * Therefore we use the FTM2 CH0 on PTA10 drive FTM_CLKIN0 (PCT12) + * and use this at a 4Mhz clock for FTM0 and FTM3. + * + * The input frequencies avaialble from FTM2 are 56,28,14,7,3.5 + * So a onshot mode at 8Mhz is not possible. We will use 4Mhz + * + * FTM0 will drive FMU_CH1-6, FTM3 will drive IO_CH1-8 */ #if !defined(BOARD_PWM_FREQ) #define BOARD_PWM_FREQ 1000000 #endif #if !defined(BOARD_ONESHOT_FREQ) -#define BOARD_ONESHOT_FREQ 8000000 +#define BOARD_ONESHOT_FREQ 4000000 #endif -#define MAX_CHANNELS_PER_TIMER 4 -#define STM32_TIM8_BASE 0 -#define STM32_TIM1_BASE 0 -#define ATIM_BDTR_MOE 0 -#define CCMR_C1_CAPTURE_INIT 0 -#define GTIM_CCER_CC1E 0 -#define GTIM_DIER_CC1IE 0 -#define CCMR_C1_PWMOUT_INIT 0 -#define STM32_GTIM_CCMR1_OFFSET 0 -#define STM32_GTIM_CCR1_OFFSET 0 -#define STM32_GTIM_CCER_OFFSET -#define STM32_GTIM_EGR_OFFSET 0 -#define modifyreg32(r,c,s) +#define FTM_SRC_CLOCK_FREQ 4000000 -#define GTIM_SR_UIF (1 << 0) /* Bit 0: Update interrupt flag */ -#define GTIM_SR_CC1IF (1 << 1) /* Bit 1: Capture/compare 1 interrupt flag */ -#define GTIM_SR_CC2IF (1 << 2) /* Bit 2: Capture/Compare 2 interrupt flag (TIM2-5,9,12,&15 only) */ -#define GTIM_SR_CC3IF (1 << 3) /* Bit 3: Capture/Compare 3 interrupt flag (TIM2-5 only) */ -#define GTIM_SR_CC4IF (1 << 4) /* Bit 4: Capture/Compare 4 interrupt flag (TIM2-5 only) */ -#define GTIM_SR_COMIF (1 << 5) /* Bit 5: COM interrupt flag (TIM15-17 only) */ -#define GTIM_SR_TIF (1 << 6) /* Bit 6: Trigger interrupt Flag (TIM2-5,9,12&15-17 only) */ -#define GTIM_SR_BIF (1 << 7) /* Bit 7: Break interrupt flag (TIM15-17 only) */ -#define GTIM_SR_CC1OF (1 << 9) /* Bit 9: Capture/Compare 1 Overcapture flag */ -#define GTIM_SR_CC2OF (1 << 10) /* Bit 10: Capture/Compare 2 Overcapture flag (TIM2-5,9,12&15 only) */ -#define GTIM_SR_CC3OF (1 << 11) /* Bit 11: Capture/Compare 3 Overcapture flag (TIM2-5 only) */ -#define GTIM_SR_CC4OF (1 << 12) /* Bit 12: Capture/Compare 4 Overcapture flag (TIM2-5 only) */ -#define GTIM_EGR_UG 0 -#define STM32_GTIM_DIER_OFFSET 0 -static volatile uint32_t dummy[19]; -#define __REG32(_reg) (*(volatile uint32_t *)(&dummy[(_reg)])) +#define MAX_CHANNELS_PER_TIMER 8 -#define _REG32(_base, _reg) __REG32(_reg) +#define _REG(_addr) (*(volatile uint32_t *)(_addr)) +#define _REG32(_base, _reg) (*(volatile uint32_t *)(_base + _reg)) #define REG(_tmr, _reg) _REG32(io_timers[_tmr].base, _reg) -#define rCR1(_tmr) REG(_tmr, 0) -#define rCR2(_tmr) REG(_tmr, 1) -#define rSMCR(_tmr) REG(_tmr, 2) -#define rDIER(_tmr) REG(_tmr, 3) -#define rSR(_tmr) REG(_tmr, 4) -#define rEGR(_tmr) REG(_tmr, 5) -#define rCCMR1(_tmr) REG(_tmr, 6) -#define rCCMR2(_tmr) REG(_tmr, 7) -#define rCCER(_tmr) REG(_tmr, 8) -#define rCNT(_tmr) REG(_tmr, 9) -#define rPSC(_tmr) REG(_tmr, 10) -#define rARR(_tmr) REG(_tmr, 11) -#define rCCR1(_tmr) REG(_tmr, 12) -#define rCCR2(_tmr) REG(_tmr, 13) -#define rCCR3(_tmr) REG(_tmr, 14) -#define rCCR4(_tmr) REG(_tmr, 15) -#define rDCR(_tmr) REG(_tmr, 16) -#define rDMAR(_tmr) REG(_tmr, 17) -#define rBDTR(_tmr) REG(_tmr, 18) -#define GTIM_SR_CCIF (GTIM_SR_CC4IF|GTIM_SR_CC3IF|GTIM_SR_CC2IF|GTIM_SR_CC1IF) -#define GTIM_SR_CCOF (GTIM_SR_CC4OF|GTIM_SR_CC3OF|GTIM_SR_CC2OF|GTIM_SR_CC1OF) +/* Timer register accessors */ -#define CCMR_C1_RESET 0x00ff -#define CCMR_C1_NUM_BITS 8 -#define CCER_C1_NUM_BITS 4 +#define rSC(_tmr) REG(_tmr,KINETIS_FTM_SC_OFFSET) +#define rCNT(_tmr) REG(_tmr,KINETIS_FTM_CNT_OFFSET) +#define rMOD(_tmr) REG(_tmr,KINETIS_FTM_MOD_OFFSET) +#define rC0SC(_tmr) REG(_tmr,KINETIS_FTM_C0SC_OFFSET) +#define rC0V(_tmr) REG(_tmr,KINETIS_FTM_C0V_OFFSET) +#define rC1SC(_tmr) REG(_tmr,KINETIS_FTM_C1SC_OFFSET) +#define rC1V(_tmr) REG(_tmr,KINETIS_FTM_C1V_OFFSET) +#define rC2SC(_tmr) REG(_tmr,KINETIS_FTM_C2SC_OFFSET) +#define rC2V(_tmr) REG(_tmr,KINETIS_FTM_C2V_OFFSET) +#define rC3SC(_tmr) REG(_tmr,KINETIS_FTM_C3SC_OFFSET) +#define rC3V(_tmr) REG(_tmr,KINETIS_FTM_C3V_OFFSET) +#define rC4SC(_tmr) REG(_tmr,KINETIS_FTM_C4SC_OFFSET) +#define rC4V(_tmr) REG(_tmr,KINETIS_FTM_C4V_OFFSET) +#define rC5SC(_tmr) REG(_tmr,KINETIS_FTM_C5SC_OFFSET) +#define rC5V(_tmr) REG(_tmr,KINETIS_FTM_C5V_OFFSET) +#define rC6SC(_tmr) REG(_tmr,KINETIS_FTM_C6SC_OFFSET) +#define rC6V(_tmr) REG(_tmr,KINETIS_FTM_C6V_OFFSET) +#define rC7SC(_tmr) REG(_tmr,KINETIS_FTM_C7SC_OFFSET) +#define rC7V(_tmr) REG(_tmr,KINETIS_FTM_C7V_OFFSET) -#define CCMR_C1_CAPTURE_INIT 0 -//(GTIM_CCMR_CCS_CCIN1 << GTIM_CCMR1_CC1S_SHIFT) | -// (GTIM_CCMR_ICPSC_NOPSC << GTIM_CCMR1_IC1PSC_SHIFT) | -// (GTIM_CCMR_ICF_NOFILT << GTIM_CCMR1_IC1F_SHIFT) +#define rCNTIN(_tmr) REG(_tmr,KINETIS_FTM_CNTIN_OFFSET) +#define rSTATUS(_tmr) REG(_tmr,KINETIS_FTM_STATUS_OFFSET) +#define rMODE(_tmr) REG(_tmr,KINETIS_FTM_MODE_OFFSET) +#define rSYNC(_tmr) REG(_tmr,KINETIS_FTM_SYNC_OFFSET) +#define rOUTINIT(_tmr) REG(_tmr,KINETIS_FTM_OUTINIT_OFFSET) +#define rOUTMASK(_tmr) REG(_tmr,KINETIS_FTM_OUTMASK_OFFSET) +#define rCOMBINE(_tmr) REG(_tmr,KINETIS_FTM_COMBINE_OFFSET) +#define rDEADTIME(_tmr) REG(_tmr,KINETIS_FTM_DEADTIME_OFFSET) +#define rEXTTRIG(_tmr) REG(_tmr,KINETIS_FTM_EXTTRIG_OFFSET) +#define rPOL(_tmr) REG(_tmr,KINETIS_FTM_POL_OFFSET) +#define rFMS(_tmr) REG(_tmr,KINETIS_FTM_FMS_OFFSET) +#define rFILTER(_tmr) REG(_tmr,KINETIS_FTM_FILTER_OFFSET) +#define rFLTCTRL(_tmr) REG(_tmr,KINETIS_FTM_FLTCTRL_OFFSET) +#define rQDCTRL(_tmr) REG(_tmr,KINETIS_FTM_QDCTRL_OFFSET) +#define rCONF(_tmr) REG(_tmr,KINETIS_FTM_CONF_OFFSET) +#define rFLTPOL(_tmr) REG(_tmr,KINETIS_FTM_FLTPOL_OFFSET) +#define rSYNCONF(_tmr) REG(_tmr,KINETIS_FTM_SYNCONF_OFFSET) +#define rINVCTRL(_tmr) REG(_tmr,KINETIS_FTM_INVCTRL_OFFSET) +#define rSWOCTRL(_tmr) REG(_tmr,KINETIS_FTM_SWOCTRL_OFFSET) +#define rPWMLOAD(_tmr) REG(_tmr,KINETIS_FTM_PWMLOAD_OFFSET) -#define CCMR_C1_PWMOUT_INIT 0 //(GTIM_CCMR_MODE_PWM1 << GTIM_CCMR1_OC1M_SHIFT) | GTIM_CCMR1_OC1PE - -#define CCMR_C1_PWMIN_INIT 0 // TBD +#define CnSC_RESET (FTM_CSC_CHF|FTM_CSC_CHIE|FTM_CSC_MSB|FTM_CSC_MSA|FTM_CSC_ELSB|FTM_CSC_ELSA|FTM_CSC_DMA) +#define CnSC_CAPTURE_INIT (FTM_CSC_CHIE|FTM_CSC_ELSB|FTM_CSC_ELSA) // Both #if defined(BOARD_PWM_DRIVE_ACTIVE_LOW) -#define CCER_C1_INIT (GTIM_CCER_CC1P | GTIM_CCER_CC1E) +#define CnSC_PWMOUT_INIT (FTM_CSC_MSB|FTM_CSC_ELSA) #else -#define CCER_C1_INIT GTIM_CCER_CC1E +#define CnSC_PWMOUT_INIT (FTM_CSC_MSB|FTM_CSC_ELSB) #endif -// NotUsed PWMOut PWMIn Capture OneShot -io_timer_channel_allocation_t channel_allocations[IOTimerChanModeSize] = { UINT8_MAX, 0, 0, 0, 0 }; + +#define CnSC_PWMIN_INIT 0 // TBD + +// NotUsed PWMOut PWMIn Capture OneShot Trigger +io_timer_channel_allocation_t channel_allocations[IOTimerChanModeSize] = { UINT16_MAX, 0, 0, 0, 0, 0 }; typedef uint8_t io_timer_allocation_t; /* big enough to hold MAX_IO_TIMERS */ @@ -187,47 +174,43 @@ static int io_timer_handler(uint16_t timer_index) const io_timers_t *tmr = &io_timers[timer_index]; - /* What is pending and enabled? */ + /* What is pending */ - uint16_t statusr = rSR(timer_index); - uint16_t enabled = rDIER(timer_index) & GTIM_SR_CCIF; + uint32_t statusr = rSTATUS(timer_index); + + /* Acknowledge all that are pending */ + + rSTATUS(timer_index) = 0; /* Iterate over the timer_io_channels table */ for (unsigned chan_index = tmr->first_channel_index; chan_index <= tmr->last_channel_index; chan_index++) { - uint16_t masks = timer_io_channels[chan_index].masks; + uint16_t chan = 1 << chan_index; - /* Do we have an enabled channel */ + if (statusr & chan) { - if (enabled & masks) { + io_timer_channel_stats[chan_index].isr_cout++; + /* Call the client to read the rCnV etc and clear the CHnF */ - if (statusr & masks & GTIM_SR_CCIF) { - - io_timer_channel_stats[chan_index].isr_cout++; - - /* Call the client to read the CCxR etc and clear the CCxIF */ - - if (channel_handlers[chan_index].callback) { - channel_handlers[chan_index].callback(channel_handlers[chan_index].context, tmr, - chan_index, &timer_io_channels[chan_index], - now, count); - } + if (channel_handlers[chan_index].callback) { + channel_handlers[chan_index].callback(channel_handlers[chan_index].context, tmr, + chan_index, &timer_io_channels[chan_index], + now, count, _REG32(tmr->base, KINETIS_FTM_CV_OFFSET(chan_index))); } + } - if (statusr & masks & GTIM_SR_CCOF) { + /* Did it set again during call out ?*/ - /* Error we has a second edge before we cleared CCxR */ + if (rSTATUS(timer_index) & chan) { - io_timer_channel_stats[chan_index].overflows++; - } + /* Error we has a second edge before we serviced the fist */ + + io_timer_channel_stats[chan_index].overflows++; } } - /* Clear all the SR bits for interrupt enabled channels only */ - - rSR(timer_index) = ~(statusr & (enabled | enabled << 8)); return 0; } @@ -474,35 +457,42 @@ static int timer_set_rate(unsigned timer, unsigned rate) { /* configure the timer to update at the desired rate */ - rARR(timer) = BOARD_PWM_FREQ / rate; + rMOD(timer) = (BOARD_PWM_FREQ / rate) - 1; /* generate an update event; reloads the counter and all registers */ - rEGR(timer) = GTIM_EGR_UG; + rSYNC(timer) = (FTM_SYNC_SWSYNC | FTM_SYNC_REINIT); return 0; } - +static inline uint32_t div2psc(int div) +{ + return 31 - __builtin_clz(div); +} static inline void io_timer_set_oneshot_mode(unsigned timer) { /* Ideally, we would want per channel One pulse mode in HW - * Alas OPE stops the Timer not the channel + * Alas The FTM anly support onshot capture) * todo:We can do this in an ISR later * But since we do not have that * We try to get the longest rate we can. - * On 16 bit timers this is 8.1 Ms. - * On 32 but timers this is 536870.912 + * On 16 bit timers this is 4.68 Ms. */ - rARR(timer) = 0xffffffff; - rPSC(timer) = (io_timers[timer].clock_freq / BOARD_ONESHOT_FREQ) - 1; - rEGR(timer) = GTIM_EGR_UG; + irqstate_t flags = px4_enter_critical_section(); + rSC(timer) &= ~(FTM_SC_CLKS_MASK | FTM_SC_PS_MASK); + rMOD(timer) = 0xffff; + rSC(timer) |= (FTM_SC_CLKS_EXTCLK | div2psc(FTM_SRC_CLOCK_FREQ / BOARD_ONESHOT_FREQ)); + px4_leave_critical_section(flags); } static inline void io_timer_set_PWM_mode(unsigned timer) { - rPSC(timer) = (io_timers[timer].clock_freq / BOARD_PWM_FREQ) - 1; + irqstate_t flags = px4_enter_critical_section(); + rSC(timer) &= ~(FTM_SC_CLKS_MASK | FTM_SC_PS_MASK); + rSC(timer) |= (FTM_SC_CLKS_EXTCLK | div2psc(FTM_SRC_CLOCK_FREQ / BOARD_PWM_FREQ)); + px4_leave_critical_section(flags); } void io_timer_trigger(void) @@ -528,7 +518,7 @@ void io_timer_trigger(void) irqstate_t flags = px4_enter_critical_section(); for (actions = 0; action_cache[actions] != 0 && actions < MAX_IO_TIMERS; actions++) { - _REG32(action_cache[actions], STM32_GTIM_EGR_OFFSET) |= GTIM_EGR_UG; + _REG32(action_cache[actions], KINETIS_FTM_SYNC_OFFSET) |= (FTM_SYNC_SWSYNC | FTM_SYNC_REINIT); } px4_leave_critical_section(flags); @@ -548,29 +538,20 @@ int io_timer_init_timer(unsigned timer) /* enable the timer clock before we try to talk to it */ - modifyreg32(io_timers[timer].clock_register, 0, io_timers[timer].clock_bit); + uint32_t regval = _REG(io_timers[timer].clock_register); + regval |= io_timers[timer].clock_bit; + _REG(io_timers[timer].clock_register) = regval; /* disable and configure the timer */ - rCR1(timer) = 0; - rCR2(timer) = 0; - rSMCR(timer) = 0; - rDIER(timer) = 0; - rCCER(timer) = 0; - rCCMR1(timer) = 0; - rCCMR2(timer) = 0; - rCCR1(timer) = 0; - rCCR2(timer) = 0; - rCCR3(timer) = 0; - rCCR4(timer) = 0; - rCCER(timer) = 0; - rDCR(timer) = 0; - if ((io_timers[timer].base == STM32_TIM1_BASE) || (io_timers[timer].base == STM32_TIM8_BASE)) { + rSC(timer) = FTM_SC_CLKS_NONE; + rCNT(timer) = 0; - /* master output enable = on */ + /* Set to run in debug mode */ - rBDTR(timer) = ATIM_BDTR_MOE; - } + rCONF(timer) |= FTM_CONF_BDMMODE_MASK; + + /* enable the timer */ io_timer_set_PWM_mode(timer); @@ -653,33 +634,23 @@ int io_timer_set_rate(unsigned timer, unsigned rate) int io_timer_channel_init(unsigned channel, io_timer_channel_mode_t mode, channel_handler_t channel_handler, void *context) { - - uint32_t gpio = 0; - uint32_t clearbits = CCMR_C1_RESET; - uint32_t setbits = CCMR_C1_CAPTURE_INIT; - uint32_t ccer_setbits = CCER_C1_INIT; - uint32_t dier_setbits = GTIM_DIER_CC1IE; + uint32_t gpio = timer_io_channels[channel].gpio_in; + uint32_t clearbits = CnSC_RESET; + uint32_t setbits = CnSC_CAPTURE_INIT; /* figure out the GPIO config first */ switch (mode) { - // intentional fallthrough case IOTimerChanMode_OneShot: case IOTimerChanMode_PWMOut: - ccer_setbits = 0; - dier_setbits = 0; - setbits = CCMR_C1_PWMOUT_INIT; + case IOTimerChanMode_Trigger: + setbits = CnSC_PWMOUT_INIT; + gpio = 0; break; case IOTimerChanMode_PWMIn: - setbits = CCMR_C1_PWMIN_INIT; - gpio = timer_io_channels[channel].gpio_in; - break; - case IOTimerChanMode_Capture: - setbits = CCMR_C1_CAPTURE_INIT; - gpio = timer_io_channels[channel].gpio_in; break; case IOTimerChanMode_NotUsed: @@ -709,47 +680,21 @@ int io_timer_channel_init(unsigned channel, io_timer_channel_mode_t mode, unsigned timer = channels_timer(channel); - (void)timer; /* configure the channel */ - uint32_t shifts = timer_io_channels[channel].timer_channel - 1; + uint32_t chan = timer_io_channels[channel].timer_channel - 1; - /* Map shifts timer channel 1-4 to 0-3 */ - - uint32_t ccmr_offset = STM32_GTIM_CCMR1_OFFSET + ((shifts >> 1) * sizeof(uint32_t)); - uint32_t ccr_offset = STM32_GTIM_CCR1_OFFSET + (shifts * sizeof(uint32_t)); - - clearbits <<= (shifts & 1) * CCMR_C1_NUM_BITS; - setbits <<= (shifts & 1) * CCMR_C1_NUM_BITS; - - uint16_t rvalue = REG(timer, ccmr_offset); + uint16_t rvalue = REG(timer, KINETIS_FTM_CSC_OFFSET(chan)); rvalue &= ~clearbits; rvalue |= setbits; - REG(timer, ccmr_offset) = rvalue; + REG(timer, KINETIS_FTM_CSC_OFFSET(chan)) = rvalue; - /* - * The beauty here is that per DocID018909 Rev 8 18.3.5 Input capture mode - * As soon as CCxS (in SSMRx becomes different from 00, the channel is configured - * in input and the TIMx_CCR1 register becomes read-only. - * so the next line does nothing in capture mode and initializes an PWM out to - * 0 - */ - - REG(timer, ccr_offset) = 0; - - /* on PWM Out ccer_setbits is 0 */ - - clearbits = 0;///(GTIM_CCER_CC1E | GTIM_CCER_CC1P | GTIM_CCER_CC1NP) << (shifts * CCER_C1_NUM_BITS); - setbits = ccer_setbits << (shifts * CCER_C1_NUM_BITS); - rvalue = rCCER(timer); - rvalue &= ~clearbits; - rvalue |= setbits; - rCCER(timer) = rvalue; + //if (gpio){ TODO: NEEDED? + REG(timer, KINETIS_FTM_CV_OFFSET(0)) = 0; channel_handlers[channel].callback = channel_handler; channel_handlers[channel].context = context; - rDIER(timer) |= dier_setbits << shifts; px4_leave_critical_section(flags); } @@ -758,29 +703,34 @@ int io_timer_channel_init(unsigned channel, io_timer_channel_mode_t mode, int io_timer_set_enable(bool state, io_timer_channel_mode_t mode, io_timer_channel_allocation_t masks) { - + typedef struct action_cache_rp_t { + uint32_t cnsc_offset; + uint32_t cnsc_value; + uint32_t gpio; + } action_cache_rp_t; struct action_cache_t { - uint32_t ccer_clearbits; - uint32_t ccer_setbits; - uint32_t dier_setbits; - uint32_t dier_clearbits; uint32_t base; - uint32_t gpio[MAX_CHANNELS_PER_TIMER]; + uint32_t index; + action_cache_rp_t cnsc[MAX_CHANNELS_PER_TIMER]; } action_cache[MAX_IO_TIMERS]; + memset(action_cache, 0, sizeof(action_cache)); - uint32_t dier_bit = state ? GTIM_DIER_CC1IE : 0; - uint32_t ccer_bit = state ? CCER_C1_INIT : 0; + uint32_t bits = state ? CnSC_PWMOUT_INIT : 0; switch (mode) { case IOTimerChanMode_NotUsed: case IOTimerChanMode_PWMOut: case IOTimerChanMode_OneShot: - dier_bit = 0; + case IOTimerChanMode_Trigger: break; case IOTimerChanMode_PWMIn: case IOTimerChanMode_Capture: + if (state) { + bits |= FTM_CSC_CHIE; + } + break; default: @@ -810,55 +760,59 @@ int io_timer_set_enable(bool state, io_timer_channel_mode_t mode, io_timer_chann for (int chan_index = 0; masks != 0 && chan_index < MAX_TIMER_IO_CHANNELS; chan_index++) { if (masks & (1 << chan_index)) { masks &= ~(1 << chan_index); - uint32_t shifts = timer_io_channels[chan_index].timer_channel - 1; - uint32_t timer = channels_timer(chan_index); - action_cache[timer].base = io_timers[timer].base; - action_cache[timer].ccer_clearbits |= CCER_C1_INIT << (shifts * CCER_C1_NUM_BITS); - action_cache[timer].ccer_setbits |= ccer_bit << (shifts * CCER_C1_NUM_BITS); - action_cache[timer].dier_clearbits |= GTIM_DIER_CC1IE << shifts; - action_cache[timer].dier_setbits |= dier_bit << shifts; - if ((state && (mode == IOTimerChanMode_PWMOut || mode == IOTimerChanMode_OneShot))) { - action_cache[timer].gpio[shifts] = timer_io_channels[chan_index].gpio_out; + if (io_timer_validate_channel_index(chan_index) == 0) { + uint32_t chan = timer_io_channels[chan_index].timer_channel - 1; + uint32_t timer = channels_timer(chan_index); + action_cache[timer].base = io_timers[timer].base; + action_cache[timer].cnsc[action_cache[timer].index].cnsc_offset = io_timers[timer].base + KINETIS_FTM_CSC_OFFSET(chan); + action_cache[timer].cnsc[action_cache[timer].index].cnsc_value = bits; + + if ((state && + (mode == IOTimerChanMode_PWMOut || + mode == IOTimerChanMode_OneShot || + mode == IOTimerChanMode_Trigger))) { + action_cache[timer].cnsc[action_cache[timer].index].gpio = timer_io_channels[chan_index].gpio_out; + } + + action_cache[timer].index++; } } } irqstate_t flags = px4_enter_critical_section(); - for (unsigned actions = 0; actions < arraySize(action_cache) && action_cache[actions].base != 0 ; actions++) { - uint32_t rvalue = 0;//_REG32(action_cache[actions].base, STM32_GTIM_CCER_OFFSET); - rvalue &= ~action_cache[actions].ccer_clearbits; - rvalue |= action_cache[actions].ccer_setbits; - //_REG32(action_cache[actions].base, STM32_GTIM_CCER_OFFSET) = rvalue; - uint32_t after = rvalue ;//& (GTIM_CCER_CC1E | GTIM_CCER_CC2E | GTIM_CCER_CC3E | GTIM_CCER_CC4E); - rvalue = _REG32(action_cache[actions].base, STM32_GTIM_DIER_OFFSET); - rvalue &= ~action_cache[actions].dier_clearbits; - rvalue |= action_cache[actions].dier_setbits; - _REG32(action_cache[actions].base, STM32_GTIM_DIER_OFFSET) = rvalue; + for (unsigned actions = 0; actions < arraySize(action_cache); actions++) { + uint32_t any_on = 0; + if (action_cache[actions].base != 0) { + for (int index = 0; index < action_cache[actions].index; index++) { - /* Any On ?*/ - - if (after != 0) { - - /* force an update to preload all registers */ - rEGR(actions) = GTIM_EGR_UG; - - for (unsigned chan = 0; chan < arraySize(action_cache[actions].gpio); chan++) { - if (action_cache[actions].gpio[chan]) { - px4_arch_configgpio(action_cache[actions].gpio[chan]); - action_cache[actions].gpio[chan] = 0; + if (action_cache[actions].cnsc[index].gpio) { + px4_arch_configgpio(action_cache[actions].cnsc[index].gpio); } + + _REG(action_cache[actions].cnsc[index].cnsc_offset) = action_cache[actions].cnsc[index].cnsc_value; + any_on |= action_cache[actions].cnsc[index].cnsc_value; } - /* arm requires the timer be enabled */ - rCR1(actions) = 0; // |= GTIM_CR1_CEN | GTIM_CR1_ARPE; + /* Any On ?*/ - } else { + /* Assume not */ + uint32_t regval = _REG32(action_cache[actions].base, KINETIS_FTM_SC_OFFSET); + regval &= ~(FTM_SC_CLKS_MASK); - rCR1(actions) = 0; + if (any_on != 0) { + + /* force an update to preload all registers */ + _REG32(action_cache[actions].base, KINETIS_FTM_SYNC_OFFSET) |= (FTM_SYNC_SWSYNC | FTM_SYNC_REINIT); + + /* arm requires the timer be enabled */ + regval |= (FTM_SC_CLKS_EXTCLK); + } + + _REG32(action_cache[actions].base, KINETIS_FTM_SC_OFFSET) = regval; } } @@ -873,7 +827,9 @@ int io_timer_set_ccr(unsigned channel, uint16_t value) int mode = io_timer_get_channel_mode(channel); if (rv == 0) { - if ((mode != IOTimerChanMode_PWMOut) && (mode != IOTimerChanMode_OneShot)) { + if ((mode != IOTimerChanMode_PWMOut) && + (mode != IOTimerChanMode_OneShot) && + (mode != IOTimerChanMode_Trigger)) { rv = -EIO; @@ -881,7 +837,7 @@ int io_timer_set_ccr(unsigned channel, uint16_t value) /* configure the channel */ - REG(channels_timer(channel), timer_io_channels[channel].ccr_offset) = value; + REG(channels_timer(channel), KINETIS_FTM_CV_OFFSET(timer_io_channels[channel].timer_channel - 1)) = value; } } @@ -895,8 +851,10 @@ uint16_t io_channel_get_ccr(unsigned channel) if (io_timer_validate_channel_index(channel) == 0) { int mode = io_timer_get_channel_mode(channel); - if ((mode == IOTimerChanMode_PWMOut) || (mode == IOTimerChanMode_OneShot)) { - value = REG(channels_timer(channel), timer_io_channels[channel].ccr_offset); + if ((mode == IOTimerChanMode_PWMOut) || + (mode == IOTimerChanMode_OneShot) || + (mode == IOTimerChanMode_Trigger)) { + value = REG(channels_timer(channel), KINETIS_FTM_CV_OFFSET(timer_io_channels[channel].timer_channel - 1)); } } diff --git a/src/drivers/kinetis/drv_io_timer.h b/src/drivers/kinetis/drv_io_timer.h index 6f19579d3f..ca65702c8c 100644 --- a/src/drivers/kinetis/drv_io_timer.h +++ b/src/drivers/kinetis/drv_io_timer.h @@ -46,7 +46,7 @@ __BEGIN_DECLS /* configuration limits */ #define MAX_IO_TIMERS 4 -#define MAX_TIMER_IO_CHANNELS 8 +#define MAX_TIMER_IO_CHANNELS 16 #define MAX_LED_TIMERS 2 #define MAX_TIMER_LED_CHANNELS 6 @@ -63,7 +63,7 @@ typedef enum io_timer_channel_mode_t { IOTimerChanModeSize } io_timer_channel_mode_t; -typedef uint8_t io_timer_channel_allocation_t; /* big enough to hold MAX_TIMER_IO_CHANNELS */ +typedef uint16_t io_timer_channel_allocation_t; /* big enough to hold MAX_TIMER_IO_CHANNELS */ /* array of timers dedicated to PWM in and out and capture use *** Note that the clock_freq is set to the source in the clock tree that @@ -74,30 +74,28 @@ typedef uint8_t io_timer_channel_allocation_t; /* big enough to hold MAX_TIMER_I *** the resulting PSC will be one and the timer will count at it's clock frequency. */ typedef struct io_timers_t { - uint32_t base; - uint32_t clock_register; - uint32_t clock_bit; - uint32_t clock_freq; - uint32_t vectorno; - uint32_t first_channel_index; - uint32_t last_channel_index; + uint32_t base; /* Base address of the timer */ + uint32_t clock_register; /* SIM_SCGCn */ + uint32_t clock_bit; /* SIM_SCGCn bit pos */ + uint32_t vectorno; /* IRQ number */ + uint32_t first_channel_index; /* 0 based index in timer_io_channels */ + uint32_t last_channel_index; /* 0 based index in timer_io_channels */ xcpt_t handler; } io_timers_t; /* array of channels in logical order */ typedef struct timer_io_channels_t { - uint32_t gpio_out; - uint32_t gpio_in; - uint8_t timer_index; - uint8_t timer_channel; - uint16_t masks; - uint8_t ccr_offset; + uint32_t gpio_out; /* The timer channel GPIO for PWM */ + uint32_t gpio_in; /* The timer channel GPIO for Capture */ + uint8_t timer_index; /* 0 based index in the io_timers_t table */ + uint8_t timer_channel; /* 1 based channel index GPIO_FTMt_CHcIN = c+1) */ } timer_io_channels_t; typedef void (*channel_handler_t)(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); + hrt_abstime isrs_time, uint16_t isrs_rcnt, + uint16_t capture); /* supplied by board-specific code */