From 220d2f21de970ab71ccc845db23a85b99da5e0d4 Mon Sep 17 00:00:00 2001 From: Pavel Kirienko Date: Thu, 29 Oct 2015 11:10:22 +0300 Subject: [PATCH 1/4] PWM moved to PIO1_8 --- firmware/lpc_chip_11cxx_lib/src/timer_11xx.c | 122 +++++++++++++++++++ firmware/src/sys/board.cpp | 115 +++++++++-------- 2 files changed, 185 insertions(+), 52 deletions(-) create mode 100755 firmware/lpc_chip_11cxx_lib/src/timer_11xx.c diff --git a/firmware/lpc_chip_11cxx_lib/src/timer_11xx.c b/firmware/lpc_chip_11cxx_lib/src/timer_11xx.c new file mode 100755 index 0000000..a97a86c --- /dev/null +++ b/firmware/lpc_chip_11cxx_lib/src/timer_11xx.c @@ -0,0 +1,122 @@ +/* + * @brief 16/32-bit Timer/PWM control functions + * + * @note + * Copyright(C) NXP Semiconductors, 2012 + * All rights reserved. + * + * @par + * Software that is described herein is for illustrative purposes only + * which provides customers with programming information regarding the + * LPC products. This software is supplied "AS IS" without any warranties of + * any kind, and NXP Semiconductors and its licensor disclaim any and + * all warranties, express or implied, including all implied warranties of + * merchantability, fitness for a particular purpose and non-infringement of + * intellectual property rights. NXP Semiconductors assumes no responsibility + * or liability for the use of the software, conveys no license or rights under any + * patent, copyright, mask work right, or any other intellectual property rights in + * or to any products. NXP Semiconductors reserves the right to make changes + * in the software without notification. NXP Semiconductors also makes no + * representation or warranty that such application will be suitable for the + * specified use without further testing or modification. + * + * @par + * Permission to use, copy, modify, and distribute this software and its + * documentation is hereby granted, under NXP Semiconductors' and its + * licensor's relevant copyrights in the software, without fee, provided that it + * is used in conjunction with NXP Semiconductors microcontrollers. This + * copyright, permission, and disclaimer notice must appear in all copies of + * this code. + */ + +#include "chip.h" + +#if __GNUC__ +# pragma GCC diagnostic ignored "-Wsign-conversion" +# pragma GCC diagnostic ignored "-Wconversion" +# pragma GCC diagnostic ignored "-Wmissing-declarations" +# pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +/***************************************************************************** + * Private types/enumerations/variables + ****************************************************************************/ + +/***************************************************************************** + * Public types/enumerations/variables + ****************************************************************************/ + +/***************************************************************************** + * Private functions + ****************************************************************************/ + +/* Returns clock index for a specific timer referenced by IP block address */ +STATIC CHIP_SYSCTL_CLOCK_T Chip_TIMER_GetClock(LPC_TIMER_T *pTMR) +{ + CHIP_SYSCTL_CLOCK_T tmrClk; + if (pTMR == LPC_TIMER32_1) { + tmrClk = SYSCTL_CLOCK_CT32B1; + } + else if (pTMR == LPC_TIMER16_0) { + tmrClk = SYSCTL_CLOCK_CT16B0; + } + else if (pTMR == LPC_TIMER16_1) { + tmrClk = SYSCTL_CLOCK_CT16B1; + } + else { + tmrClk = SYSCTL_CLOCK_CT32B0; + } + + return tmrClk; +} + +/***************************************************************************** + * Public functions + ****************************************************************************/ + +/* Initialize a timer */ +void Chip_TIMER_Init(LPC_TIMER_T *pTMR) +{ + Chip_Clock_EnablePeriphClock(Chip_TIMER_GetClock(pTMR)); +} + +/* Shutdown a timer */ +void Chip_TIMER_DeInit(LPC_TIMER_T *pTMR) +{ + Chip_Clock_DisablePeriphClock(Chip_TIMER_GetClock(pTMR)); +} + +/* Resets the timer terminal and prescale counts to 0 */ +void Chip_TIMER_Reset(LPC_TIMER_T *pTMR) +{ + uint32_t reg; + + /* Disable timer, set terminal count to non-0 */ + reg = pTMR->TCR; + pTMR->TCR = 0; + pTMR->TC = 1; + + /* Reset timer counter */ + pTMR->TCR = TIMER_RESET; + + /* Wait for terminal count to clear */ + while (pTMR->TC != 0) {} + + /* Restore timer state */ + pTMR->TCR = reg; +} + +/* Sets external match control (MATn.matchnum) pin control */ +void Chip_TIMER_ExtMatchControlSet(LPC_TIMER_T *pTMR, int8_t initial_state, + TIMER_PIN_MATCH_STATE_T matchState, int8_t matchnum) +{ + uint32_t mask, reg; + + /* Clear bits corresponding to selected match register */ + mask = (1 << matchnum) | (0x03 << (4 + (matchnum * 2))); + reg = pTMR->EMR &= ~mask; + + /* Set new configuration for selected match register */ + pTMR->EMR = reg | (((uint32_t) initial_state) << matchnum) | + (((uint32_t) matchState) << (4 + (matchnum * 2))); +} diff --git a/firmware/src/sys/board.cpp b/firmware/src/sys/board.cpp index fd448d6..c875df0 100644 --- a/firmware/src/sys/board.cpp +++ b/firmware/src/sys/board.cpp @@ -15,7 +15,6 @@ #include #include #include -#include #ifndef BOARD_OLIMEX_LPC_P11C24 #define BOARD_OLIMEX_LPC_P11C24 0 @@ -39,9 +38,6 @@ constexpr std::uint32_t TargetSystemCoreClock = 48000000; constexpr unsigned AdcReferenceMillivolts = 3300; constexpr unsigned AdcResolutionBits = 10; -constexpr unsigned PwmPortNum = 2; -constexpr unsigned PwmInputPinMask = 1U << 10; - #if BOARD_OLIMEX_LPC_P11C24 constexpr unsigned CanLedPortNum = 1; constexpr unsigned CanLedPinMask = 1U << 11; @@ -63,13 +59,9 @@ constexpr unsigned MagnetCtrlPinMask14 = (1U << 2) | (1U << 8); constexpr unsigned DipSwitchPortNum = 1; constexpr unsigned DipSwitchPinMask = 0b1111; -// TODO: DIP switch pins are not yet defined - -constexpr std::uint32_t PwmInputPeriodMinUSec = 500; -constexpr std::uint32_t PwmInputPeriodMaxUSec = 2500; -constexpr std::uint32_t PwmInputTimeoutUSec = 100000; -static std::uint32_t pwm_input_period_usec; -static uavcan::MonotonicTime last_pwm_input_update_ts; +constexpr std::uint16_t PwmInputPeriodMinUSec = 500; +constexpr std::uint16_t PwmInputPeriodMaxUSec = 2500; +static std::uint16_t pwm_input_period_usec; struct PinMuxGroup { @@ -89,6 +81,8 @@ constexpr PinMuxGroup pinmux[] = // PIO0 { IOCON_PIO0_11, IOCON_FUNC2 | IOCON_MODE_INACT | IOCON_ADMODE_EN |IOCON_OPENDRAIN_EN }, // Vout_ADC + //{ IOCON_PIO0_2, IOCON_FUNC2 | IOCON_HYS_EN | IOCON_MODE_PULLDOWN }, // PWM + // PIO1 { IOCON_PIO1_10, IOCON_FUNC1 | IOCON_MODE_INACT | IOCON_ADMODE_EN |IOCON_OPENDRAIN_EN }, // Vin_ADC @@ -103,14 +97,14 @@ constexpr PinMuxGroup pinmux[] = { IOCON_PIO1_2, IOCON_FUNC1 | IOCON_MODE_PULLDOWN | IOCON_HYS_EN | IOCON_DIGMODE_EN }, // PUMP SW2 { IOCON_PIO1_4, IOCON_FUNC0 | IOCON_MODE_PULLDOWN | IOCON_HYS_EN | IOCON_DIGMODE_EN }, // PUMP SW4 + { IOCON_PIO1_8, IOCON_FUNC1 | IOCON_HYS_EN | IOCON_MODE_PULLDOWN }, // PWM + // PIO2 { IOCON_PIO2_0, IOCON_FUNC0 | IOCON_HYS_EN | IOCON_MODE_PULLDOWN }, // Status LED #if !BOARD_OLIMEX_LPC_P11C24 { IOCON_PIO2_6, IOCON_FUNC0 }, // CAN LED #endif - { IOCON_PIO2_10, IOCON_FUNC0 | IOCON_HYS_EN | IOCON_MODE_PULLDOWN }, // PWM - { IOCON_PIO2_1, IOCON_FUNC0 | IOCON_HYS_EN | IOCON_MODE_PULLDOWN | IOCON_DIGMODE_EN }, // CTRL3 { IOCON_PIO2_7, IOCON_FUNC0 | IOCON_HYS_EN | IOCON_MODE_PULLDOWN | IOCON_DIGMODE_EN }, // CTRL2 @@ -227,13 +221,6 @@ void initGpio() gpio::makeOutputsAndSet(PumpSwitchPortNum, PumpSwitchPinMask, 0); gpio::makeOutputsAndSet(MagnetCtrlPortNum, MagnetCtrlPinMask23 | MagnetCtrlPinMask14, 0); - - // PWM input config - LPC_GPIO[PwmPortNum].IBE |= PwmInputPinMask; - LPC_GPIO[PwmPortNum].IE |= PwmInputPinMask; - - //NVIC_EnableIRQ(EINT2_IRQn); - NVIC_SetPriority(EINT2_IRQn, 0); // Highest } void initAdc() @@ -256,6 +243,23 @@ void initUart() Chip_UART_TXEnable(LPC_USART); } +void initPwmCapture() +{ + Chip_TIMER_Init(LPC_TIMER16_1); + // 1 usec per tick + Chip_TIMER_PrescaleSet(LPC_TIMER16_1, (TargetSystemCoreClock / 1000000U) - 1U); + // Hardware PWM capture (edges will be initialized in the IRQ handler) + Chip_TIMER_CaptureEnableInt(LPC_TIMER16_1, 0); + // PWM timeout detection + Chip_TIMER_SetMatch(LPC_TIMER16_1, 0, 0xFFFF); // 65.535 ms timeout (~15 Hz) + Chip_TIMER_MatchEnableInt(LPC_TIMER16_1, 0); + // Start + Chip_TIMER_Enable(LPC_TIMER16_1); + // Enabling the IRQ + NVIC_EnableIRQ(TIMER_16_1_IRQn); + NVIC_SetPriority(TIMER_16_1_IRQn, 0); // Highest priority +} + void init() { Chip_SYSCTL_SetBODLevels(SYSCTL_BODRSTLVL_2_06V, SYSCTL_BODINTVAL_RESERVED1); @@ -266,6 +270,7 @@ void init() initGpio(); initAdc(); initUart(); + initPwmCapture(); resetWatchdog(); } @@ -369,8 +374,8 @@ unsigned getSupplyVoltageInMillivolts() old_value = new_value; - x *= 5; //should be x*=5.5 - x += 650; //Poor man's optimizatin to not unintegerify the math, it's within 100mV - + x *= 5; //should be x*=5.5 + x += 650; //Poor man's optimizatin to not unintegerify the math, it's within 100mV - if (x < 4500) //Under 4500mV Vref drops, mesurements useless { x = 0; @@ -394,15 +399,8 @@ unsigned getOutVoltageInVolts() return x / 10; } -#if __GNUC__ -__attribute__((optimize(1))) // Fails -#endif unsigned getPwmInputPeriodInMicroseconds() { - if ((uavcan_lpc11c24::clock::getMonotonic() - last_pwm_input_update_ts).toUSec() > PwmInputTimeoutUSec) - { - pwm_input_period_usec = 0; - } return pwm_input_period_usec; } @@ -483,42 +481,55 @@ void syslog(const char* prefix, long long integer_value, const char* suffix) extern "C" { -void PIOINT2_IRQHandler(); -void PIOINT2_IRQHandler() +void TIMER16_1_IRQHandler(); +void TIMER16_1_IRQHandler() { using namespace board; - if ((LPC_GPIO[PwmPortNum].MIS & PwmInputPinMask) != 0) - { - LPC_GPIO[PwmPortNum].IC = PwmInputPinMask; - - static uavcan::MonotonicTime prev_ts; - const auto ts = uavcan_lpc11c24::clock::getMonotonic(); // TODO: Is it safe to call it from here? - const auto diff_usec = static_cast((ts - prev_ts).toUSec()); - prev_ts = ts; + static bool rising_edge = true; - const bool input_state = (LPC_GPIO[PwmPortNum].DATA[PwmInputPinMask] & PwmInputPinMask) != 0; + if (Chip_TIMER_CapturePending(LPC_TIMER16_1, 0)) + { + if (rising_edge) + { + Chip_TIMER_CaptureRisingEdgeDisable(LPC_TIMER16_1, 0); + Chip_TIMER_CaptureFallingEdgeEnable(LPC_TIMER16_1, 0); - if (!input_state) // Updating only on trailing edge + rising_edge = false; + } + else { - last_pwm_input_update_ts = ts; + Chip_TIMER_CaptureFallingEdgeDisable(LPC_TIMER16_1, 0); + Chip_TIMER_CaptureRisingEdgeEnable(LPC_TIMER16_1, 0); - if (diff_usec >= PwmInputPeriodMinUSec && diff_usec <= PwmInputPeriodMaxUSec) + if ((LPC_TIMER16_1->CR[0] >= PwmInputPeriodMinUSec) && + (LPC_TIMER16_1->CR[0] <= PwmInputPeriodMaxUSec)) { - if (pwm_input_period_usec == 0) - { - pwm_input_period_usec = static_cast(diff_usec); - } - else - { - pwm_input_period_usec = static_cast((pwm_input_period_usec + diff_usec) / 2); - } + pwm_input_period_usec = static_cast(LPC_TIMER16_1->CR[0]); } else { - pwm_input_period_usec = 0; // Invalid value + pwm_input_period_usec = 0; } + + rising_edge = true; } + + Chip_TIMER_ClearCapture(LPC_TIMER16_1, 0); + + // this IRQ has the highest priority, so the following operation is quasi atomic + LPC_TIMER16_1->TC = LPC_TIMER16_1->TC - LPC_TIMER16_1->CR[0]; + } + + if (Chip_TIMER_MatchPending(LPC_TIMER16_1, 0)) + { + Chip_TIMER_ClearMatch(LPC_TIMER16_1, 0); + + Chip_TIMER_CaptureFallingEdgeDisable(LPC_TIMER16_1, 0); + Chip_TIMER_CaptureRisingEdgeEnable(LPC_TIMER16_1, 0); + + rising_edge = true; + pwm_input_period_usec = 0; } } From b236b5b04428b708b56c5bd460a474101c53c8e3 Mon Sep 17 00:00:00 2001 From: Pavel Kirienko Date: Thu, 29 Oct 2015 11:16:53 +0300 Subject: [PATCH 2/4] getPwmInputPeriodInMicroseconds() --> getPwmInputPulseLengthInMicroseconds() --- firmware/src/magnet/magnet.cpp | 2 +- firmware/src/sys/board.cpp | 14 ++++++-------- firmware/src/sys/board.hpp | 7 ++++++- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/firmware/src/magnet/magnet.cpp b/firmware/src/magnet/magnet.cpp index 7f18bd3..8b378be 100644 --- a/firmware/src/magnet/magnet.cpp +++ b/firmware/src/magnet/magnet.cpp @@ -200,7 +200,7 @@ void poll() { const auto supply_voltage_mV = board::getSupplyVoltageInMillivolts(); - const auto pwm_input = board::getPwmInputPeriodInMicroseconds(); + const auto pwm_input = board::getPwmInputPulseLengthInMicroseconds(); if (board::hadButtonPressEvent()) { diff --git a/firmware/src/sys/board.cpp b/firmware/src/sys/board.cpp index c875df0..131be15 100644 --- a/firmware/src/sys/board.cpp +++ b/firmware/src/sys/board.cpp @@ -61,7 +61,7 @@ constexpr unsigned DipSwitchPinMask = 0b1111; constexpr std::uint16_t PwmInputPeriodMinUSec = 500; constexpr std::uint16_t PwmInputPeriodMaxUSec = 2500; -static std::uint16_t pwm_input_period_usec; +static std::uint16_t pwm_input_pulse_usec; struct PinMuxGroup { @@ -81,8 +81,6 @@ constexpr PinMuxGroup pinmux[] = // PIO0 { IOCON_PIO0_11, IOCON_FUNC2 | IOCON_MODE_INACT | IOCON_ADMODE_EN |IOCON_OPENDRAIN_EN }, // Vout_ADC - //{ IOCON_PIO0_2, IOCON_FUNC2 | IOCON_HYS_EN | IOCON_MODE_PULLDOWN }, // PWM - // PIO1 { IOCON_PIO1_10, IOCON_FUNC1 | IOCON_MODE_INACT | IOCON_ADMODE_EN |IOCON_OPENDRAIN_EN }, // Vin_ADC @@ -399,9 +397,9 @@ unsigned getOutVoltageInVolts() return x / 10; } -unsigned getPwmInputPeriodInMicroseconds() +unsigned getPwmInputPulseLengthInMicroseconds() { - return pwm_input_period_usec; + return pwm_input_pulse_usec; } void delayUSec(std::uint8_t usec) @@ -505,11 +503,11 @@ void TIMER16_1_IRQHandler() if ((LPC_TIMER16_1->CR[0] >= PwmInputPeriodMinUSec) && (LPC_TIMER16_1->CR[0] <= PwmInputPeriodMaxUSec)) { - pwm_input_period_usec = static_cast(LPC_TIMER16_1->CR[0]); + pwm_input_pulse_usec = static_cast(LPC_TIMER16_1->CR[0]); } else { - pwm_input_period_usec = 0; + pwm_input_pulse_usec = 0; } rising_edge = true; @@ -529,7 +527,7 @@ void TIMER16_1_IRQHandler() Chip_TIMER_CaptureRisingEdgeEnable(LPC_TIMER16_1, 0); rising_edge = true; - pwm_input_period_usec = 0; + pwm_input_pulse_usec = 0; } } diff --git a/firmware/src/sys/board.hpp b/firmware/src/sys/board.hpp index f9437d1..9d6dcb5 100644 --- a/firmware/src/sys/board.hpp +++ b/firmware/src/sys/board.hpp @@ -41,7 +41,12 @@ unsigned getSupplyVoltageInMillivolts(); unsigned getOutVoltageInVolts(); -unsigned getPwmInputPeriodInMicroseconds(); +/** + * Returns pulse length of the input PWM in microseconds if the signal is present and valid. + * If PWM signal is not present, or if the pulse length not within the range [500, 2500] microseconds, + * the function will return zero. + */ +unsigned getPwmInputPulseLengthInMicroseconds(); /** * Delays execution in a busyloop for the specified amount of microseconds. From 3f728ce8e214b0ce8ea5d72c96508083a78eadb2 Mon Sep 17 00:00:00 2001 From: Pavel Kirienko Date: Thu, 29 Oct 2015 11:24:20 +0300 Subject: [PATCH 3/4] PWM capture averaging --- firmware/src/sys/board.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/firmware/src/sys/board.cpp b/firmware/src/sys/board.cpp index 131be15..bacb0c0 100644 --- a/firmware/src/sys/board.cpp +++ b/firmware/src/sys/board.cpp @@ -503,7 +503,15 @@ void TIMER16_1_IRQHandler() if ((LPC_TIMER16_1->CR[0] >= PwmInputPeriodMinUSec) && (LPC_TIMER16_1->CR[0] <= PwmInputPeriodMaxUSec)) { - pwm_input_pulse_usec = static_cast(LPC_TIMER16_1->CR[0]); + if (pwm_input_pulse_usec > 0) + { + pwm_input_pulse_usec = + static_cast((LPC_TIMER16_1->CR[0] + pwm_input_pulse_usec) / 2U); + } + else + { + pwm_input_pulse_usec = static_cast(LPC_TIMER16_1->CR[0]); + } } else { From 4dbded8fdb89281eecb32ab8bc9c956103d1d0be Mon Sep 17 00:00:00 2001 From: Pavel Kirienko Date: Thu, 29 Oct 2015 11:50:44 +0300 Subject: [PATCH 4/4] More reliable PWM capture --- firmware/src/sys/board.cpp | 53 ++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/firmware/src/sys/board.cpp b/firmware/src/sys/board.cpp index bacb0c0..a55cba6 100644 --- a/firmware/src/sys/board.cpp +++ b/firmware/src/sys/board.cpp @@ -249,13 +249,12 @@ void initPwmCapture() // Hardware PWM capture (edges will be initialized in the IRQ handler) Chip_TIMER_CaptureEnableInt(LPC_TIMER16_1, 0); // PWM timeout detection - Chip_TIMER_SetMatch(LPC_TIMER16_1, 0, 0xFFFF); // 65.535 ms timeout (~15 Hz) Chip_TIMER_MatchEnableInt(LPC_TIMER16_1, 0); // Start Chip_TIMER_Enable(LPC_TIMER16_1); // Enabling the IRQ NVIC_EnableIRQ(TIMER_16_1_IRQn); - NVIC_SetPriority(TIMER_16_1_IRQn, 0); // Highest priority + NVIC_SetPriority(TIMER_16_1_IRQn, 1); } void init() @@ -484,33 +483,42 @@ void TIMER16_1_IRQHandler() { using namespace board; - static bool rising_edge = true; + static std::int32_t rising_edge_timestamp = -1; + static constexpr unsigned CCR_RISING_EDGE = 0b101; + static constexpr unsigned CCR_FALLING_EDGE = 0b110; + + /* + * PWM edge capture interrupt + */ if (Chip_TIMER_CapturePending(LPC_TIMER16_1, 0)) { - if (rising_edge) - { - Chip_TIMER_CaptureRisingEdgeDisable(LPC_TIMER16_1, 0); - Chip_TIMER_CaptureFallingEdgeEnable(LPC_TIMER16_1, 0); + // Clearing the flag + Chip_TIMER_ClearCapture(LPC_TIMER16_1, 0); - rising_edge = false; + // Swapping polarity and processing the event + if (rising_edge_timestamp < 0) + { + LPC_TIMER16_1->CCR = CCR_FALLING_EDGE; + rising_edge_timestamp = static_cast(LPC_TIMER16_1->CR[0]); } else { - Chip_TIMER_CaptureFallingEdgeDisable(LPC_TIMER16_1, 0); - Chip_TIMER_CaptureRisingEdgeEnable(LPC_TIMER16_1, 0); + LPC_TIMER16_1->CCR = CCR_RISING_EDGE; - if ((LPC_TIMER16_1->CR[0] >= PwmInputPeriodMinUSec) && - (LPC_TIMER16_1->CR[0] <= PwmInputPeriodMaxUSec)) + const std::uint16_t duration = + static_cast(LPC_TIMER16_1->CR[0] - static_cast(rising_edge_timestamp)); + + if ((duration >= PwmInputPeriodMinUSec) && (duration <= PwmInputPeriodMaxUSec)) { if (pwm_input_pulse_usec > 0) { pwm_input_pulse_usec = - static_cast((LPC_TIMER16_1->CR[0] + pwm_input_pulse_usec) / 2U); + static_cast((duration + pwm_input_pulse_usec) / 2); } else { - pwm_input_pulse_usec = static_cast(LPC_TIMER16_1->CR[0]); + pwm_input_pulse_usec = duration; } } else @@ -518,23 +526,24 @@ void TIMER16_1_IRQHandler() pwm_input_pulse_usec = 0; } - rising_edge = true; + rising_edge_timestamp = -1; } - Chip_TIMER_ClearCapture(LPC_TIMER16_1, 0); - - // this IRQ has the highest priority, so the following operation is quasi atomic - LPC_TIMER16_1->TC = LPC_TIMER16_1->TC - LPC_TIMER16_1->CR[0]; + // Resetting the timeout interrupt + LPC_TIMER16_1->MR[0] = LPC_TIMER16_1->CR[0] + 0xFFFFU; // 65.535 ms timeout (~15 Hz) + Chip_TIMER_ClearMatch(LPC_TIMER16_1, 0); } + /* + * PWM edge timeout interrupt (will be invoked periodically as long as the PWM signal is not present) + */ if (Chip_TIMER_MatchPending(LPC_TIMER16_1, 0)) { Chip_TIMER_ClearMatch(LPC_TIMER16_1, 0); - Chip_TIMER_CaptureFallingEdgeDisable(LPC_TIMER16_1, 0); - Chip_TIMER_CaptureRisingEdgeEnable(LPC_TIMER16_1, 0); + LPC_TIMER16_1->CCR = CCR_RISING_EDGE; - rising_edge = true; + rising_edge_timestamp = -1; pwm_input_pulse_usec = 0; } }