Add InputCapture and OnePulse functionality from @stevestrong

This commit is contained in:
Roger Clark 2018-02-13 18:34:15 +11:00
parent c063a916fd
commit f928acf193
6 changed files with 225 additions and 117 deletions

View File

@ -30,6 +30,7 @@
#include "ext_interrupts.h" // for noInterrupts(), interrupts()
#include "wirish_math.h"
#include <board/board.h> // for CYCLES_PER_MICROSECOND
#include <libmaple/dma.h>
// TODO [0.1.0] Remove deprecated pieces
@ -138,7 +139,6 @@ void HardwareTimer::detachInterrupt(int channel) {
timer_detach_interrupt(this->dev, (uint8)channel);
}
void HardwareTimer::enableDMA(int channel) {
timer_dma_enable_req(this->dev, (uint8)channel);
}
@ -156,28 +156,7 @@ void HardwareTimer::setMasterModeTrGo(uint32_t mode) {
this->dev->regs.bas->CR2 |= mode;
}
/* CARLOS Changes to add encoder mode.*/
//direction of movement. (to be better described).
uint8 HardwareTimer::getDirection(){
return get_direction(this->dev);
}
//set if the encoder will count edges on one, which or both channels.
void HardwareTimer::setEdgeCounting(uint32 counting) {
(dev->regs).gen->SMCR = counting;//TIMER_SMCR_SMS_ENCODER3; //choose encoder 3, counting on
}
uint8 HardwareTimer::getEdgeCounting() {
return (dev->regs).gen->SMCR;
}
//set the polarity of counting... not sure how interesting this is..
void HardwareTimer::setPolarity(){}
/* -- Deprecated predefined instances -------------------------------------- */
HardwareTimer Timer1(1);

View File

@ -227,32 +227,53 @@ public:
* TIMER_CR2_MMS_COMPARE_OC4REF
*/
void setMasterModeTrGo(uint32_t mode);
void setSlaveFlags(uint32 flags) {
((this->dev)->regs).gen->SMCR = flags;
}
//CARLOS.
/*
added these functions to make sense for the encoder mode.
*/
//direction of movement. (to be better described).
uint8 getDirection();
uint8 getDirection() {
return get_direction(this->dev);
}
//set if the encoder will count edges on one, which or both channels.
void setEdgeCounting(uint32 counting);
uint8 getEdgeCounting(); //not sure if needed.
void setEdgeCounting(uint32 counting) {
setSlaveFlags(counting);
}
//set the polarity of counting... not sure how interesting this is..
void setPolarity();
void setPolarity(uint8 channel, uint8 pol) {
timer_cc_set_pol(this->dev, channel, pol);
}
void setInputCaptureMode(uint8 channel, timer_ic_input_select input) {
input_capture_mode(this->dev, channel, input);
}
uint8_t getInputCaptureFlag(uint8 channel) {
return ( timer_get_status(this->dev) >> channel ) & 0x1;
}
uint8_t getInputCaptureFlagOverflow(uint8 channel) {
uint8 ret = ( timer_get_status(this->dev) >> (8+channel) ) & 0x1;
if ( ret ) timer_reset_status_bit(this->dev, (8+channel)); // clear flag
return ret;
}
//add the filtering definition for the input channel.
/* Escape hatch */
/**
/**
* @brief Enable/disable DMA request for the input channel.
*/
void enableDMA(int channel);
void disableDMA(int channel);
void enableDMA(int channel);
void disableDMA(int channel);
/**
* @brief Get a pointer to the underlying libmaple timer_dev for
* this HardwareTimer instance.

View File

@ -40,7 +40,6 @@ static void pwm_mode(timer_dev *dev, uint8 channel);
static void output_compare_mode(timer_dev *dev, uint8 channel);
static void encoder_mode(timer_dev *dev, uint8 channel) ;//CARLOS
static inline void enable_irq(timer_dev *dev, timer_interrupt_id iid);
/*
@ -236,6 +235,9 @@ void timer_set_mode(timer_dev *dev, uint8 channel, timer_mode mode) {
case TIMER_ENCODER:
encoder_mode(dev, channel); //find a way to pass all the needed stuff on the 8bit var
break;
case TIMER_INPUT_CAPTURE:// code from @Cesco
input_capture_mode(dev, channel, TIMER_IC_INPUT_DEFAULT);
break;
}
}
@ -349,7 +351,10 @@ static void encoder_mode(timer_dev *dev, uint8 channel __attribute__((unused)))
timer_resume(dev);
}
void input_capture_mode(timer_dev *dev, uint8 channel, timer_ic_input_select input) {
timer_oc_set_mode(dev, channel, 0, input);
timer_cc_enable(dev, channel);
}
static void enable_adv_irq(timer_dev *dev, timer_interrupt_id id);
static void enable_bas_gen_irq(timer_dev *dev);

View File

@ -0,0 +1,67 @@
/*
* Example of the Timer Input Capture mode combined with one pulse mode
*
* This example uses:
* - Timer2 channel 1 as capture input
* - Timer2 channel 2 to generate the pulses,
* - Timer 3 to generate a PWM trigger signal for capture input
*/
#include <Streaming.h>
const uint16_t pulseDelay = 200;
const uint16_t pulseWidth = 200;
//-----------------------------------------------------------------------------
void toggle_led()
{
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
}
//-----------------------------------------------------------------------------
void setup()
{
// setup PA1 (Timer2 channel 2) to PWM (one pulse mode)
pinMode(PA1, PWM);
// setup PA0 (Timer 2 channel 1) as input (capture input mode)
pinMode(PA0, INPUT);
// stop the timers before configuring them
Timer2.pause();
Timer2.setPrescaleFactor(72); // 1 µs resolution
Timer2.setCompare(TIMER_CH2, pulseDelay);
Timer2.setOverflow(pulseWidth + pulseDelay-1);
// counter setup in one pulse mode, as slave triggered by TI1
TIMER2_BASE->CR1 = ( TIMER_CR1_OPM ); // one pulse mode
Timer2.setSlaveFlags( TIMER_SMCR_TS_TI1FP1 | TIMER_SMCR_SMS_TRIGGER );
// channel 1: capture input on rising edge
Timer2.setMode(TIMER_CH1, TIMER_INPUT_CAPTURE);
//Timer2.setPolarity(TIMER_CH1, 1); // trigger on falling edge
// channel 2: invert polarity (we want low for CNT<CCR2)
Timer2.setPolarity(TIMER_CH2, 1);
// start timer 2
Timer2.refresh();
Timer2.resume(); // let timer 2 run
// setup PA6 (Timer3 channel 1) to generate 1 ms period PWM with 10% DC
pinMode(PA6, PWM);
Timer3.pause();
Timer3.setPrescaleFactor(72); // 1 µs resolution
Timer3.setCompare(TIMER_CH1, 100);
Timer3.setOverflow(1000);
Timer3.refresh();
Timer3.resume(); // let timer 3 run
}
uint32_t t;
//-----------------------------------------------------------------------------
void loop()
{
if ( (millis()-t)>=1000 )
{
t = millis();
toggle_led();
}
}

View File

@ -0,0 +1,77 @@
/*
* Example of the Timer Input Capture mode to measure PWM pulse width and period.
*
* This example uses:
* - Timer2 channel 1 as capture input
* - Timer3 to generate a PWM trigger signal for capture input
*/
#include <Streaming.h>
const uint8_t pwmPulse = 20; // ms
const uint8_t pwmPeriod = 50; // ms
//-----------------------------------------------------------------------------
void toggle_led()
{
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
}
//-----------------------------------------------------------------------------
void setup()
{
pinMode(LED_BUILTIN, OUTPUT);
// setup PA0 (Timer 2 channel 1) as input capture mode
pinMode(PA0, INPUT);
while (!Serial); delay(1000);
Serial << "Example of the Timer Input Capture mode to measure PWM pulse width and period\n\n";
// stop the timers before configuring them
Timer2.pause();
Timer3.pause();
Timer2.setPrescaleFactor(72); // 1 microsecond resolution
// setup timer 2 channel 1 capture on rising edge
Timer2.setInputCaptureMode(TIMER_CH1, TIMER_IC_INPUT_DEFAULT); // use default input TI1
// setup timer 2 channel 2 capture on falling edge
Timer2.setInputCaptureMode(TIMER_CH2, TIMER_IC_INPUT_SWITCH); // use switched input TI1
Timer2.setPolarity(TIMER_CH2, 1); // trigger on falling edge
// counter setup as slave triggered by TI1 in reset mode
Timer2.setSlaveFlags( TIMER_SMCR_TS_TI1FP1 | TIMER_SMCR_SMS_RESET );
Timer2.refresh();
Timer2.getCompare(TIMER_CH1); // clear capture flag
Timer2.getCompare(TIMER_CH2); // clear capture flag
Timer2.resume(); // let timer 2 run
// setup PA6 (Timer3 channel 1) to generate 1 ms period PWM with 10% DC
pinMode(PA6, PWM);
Timer3.setPrescaleFactor(72); // 1 µs resolution
Timer3.setCompare(TIMER_CH1, pwmPulse*1000);
Timer3.setOverflow(pwmPeriod*1000);
Timer3.refresh();
Timer3.resume(); // let timer 3 run
// discard first reading
// wait for first period end
while ( !Timer2.getInputCaptureFlag(TIMER_CH1) );
Timer2.getCompare(TIMER_CH1); // clear capture flag
}
//-----------------------------------------------------------------------------
void loop()
{
if ( Timer2.getInputCaptureFlag(TIMER_CH2) ) // high pulse end
{
Serial << "PWM pulse width: " << Timer2.getCompare(TIMER_CH2);
}
if ( Timer2.getInputCaptureFlag(TIMER_CH1) ) // period end
{
Serial << ", period: " << Timer2.getCompare(TIMER_CH1) << endl;
toggle_led();
//delay(500); // read the values only 2 times per second
}
}

View File

@ -372,7 +372,6 @@ extern timer_dev timer14;
/* Capture/compare mode registers, common values */
#define TIMER_CCMR_CCS_OUTPUT 0x0
#define TIMER_CCMR_CCS_INPUT_TI1 0x1
#define TIMER_CCMR_CCS_INPUT_TI2 0x2
#define TIMER_CCMR_CCS_INPUT_TRC 0x3
@ -387,7 +386,7 @@ extern timer_dev timer14;
#define TIMER_CCMR1_OC1FE_BIT 2
#define TIMER_CCMR1_OC2CE (1U << TIMER_CCMR1_OC2CE_BIT)
#define TIMER_CCMR1_OC2M (0x3 << 12)
#define TIMER_CCMR1_OC2M (0x7 << 12)
#define TIMER_CCMR1_IC2F (0xF << 12)
#define TIMER_CCMR1_OC2PE (1U << TIMER_CCMR1_OC2PE_BIT)
#define TIMER_CCMR1_OC2FE (1U << TIMER_CCMR1_OC2FE_BIT)
@ -398,16 +397,16 @@ extern timer_dev timer14;
#define TIMER_CCMR1_CC2S_INPUT_TI1 (0x2 << 8)
#define TIMER_CCMR1_CC2S_INPUT_TRC (0x3 << 8)
#define TIMER_CCMR1_OC1CE (1U << TIMER_CCMR1_OC1CE_BIT)
#define TIMER_CCMR1_OC1M (0x3 << 4)
#define TIMER_CCMR1_OC1M (0x7 << 4)
#define TIMER_CCMR1_IC1F (0xF << 4)
#define TIMER_CCMR1_OC1PE (1U << TIMER_CCMR1_OC1PE_BIT)
#define TIMER_CCMR1_OC1FE (1U << TIMER_CCMR1_OC1FE_BIT)
#define TIMER_CCMR1_IC1PSC (0x3 << 2)
#define TIMER_CCMR1_CC1S 0x3
#define TIMER_CCMR1_CC1S_OUTPUT TIMER_CCMR_CCS_OUTPUT
#define TIMER_CCMR1_CC1S_INPUT_TI1 TIMER_CCMR_CCS_INPUT_TI1
#define TIMER_CCMR1_CC1S_INPUT_TI2 TIMER_CCMR_CCS_INPUT_TI2
#define TIMER_CCMR1_CC1S_INPUT_TRC TIMER_CCMR_CCS_INPUT_TRC
#define TIMER_CCMR1_CC1S_OUTPUT 0x0
#define TIMER_CCMR1_CC1S_INPUT_TI1 0x1
#define TIMER_CCMR1_CC1S_INPUT_TI2 0x2
#define TIMER_CCMR1_CC1S_INPUT_TRC 0x3
/* Capture/compare mode register 2 (CCMR2) */
@ -425,10 +424,10 @@ extern timer_dev timer14;
#define TIMER_CCMR2_OC4FE (1U << TIMER_CCMR2_OC4FE_BIT)
#define TIMER_CCMR2_IC4PSC (0x3 << 10)
#define TIMER_CCMR2_CC4S (0x3 << 8)
#define TIMER_CCMR2_CC4S_OUTPUT (TIMER_CCMR_CCS_OUTPUT << 8)
#define TIMER_CCMR2_CC4S_INPUT_TI1 (TIMER_CCMR_CCS_INPUT_TI1 << 8)
#define TIMER_CCMR2_CC4S_INPUT_TI2 (TIMER_CCMR_CCS_INPUT_TI2 << 8)
#define TIMER_CCMR2_CC4S_INPUT_TRC (TIMER_CCMR_CCS_INPUT_TRC << 8)
#define TIMER_CCMR2_CC4S_OUTPUT (0x0 << 8)
#define TIMER_CCMR2_CC4S_INPUT_TI4 (0x1 << 8)
#define TIMER_CCMR2_CC4S_INPUT_TI3 (0x2 << 8)
#define TIMER_CCMR2_CC4S_INPUT_TRC (0x3 << 8)
#define TIMER_CCMR2_OC3CE (1U << TIMER_CCMR2_OC3CE_BIT)
#define TIMER_CCMR2_OC3M (0x3 << 4)
#define TIMER_CCMR2_IC3F (0xF << 4)
@ -436,10 +435,10 @@ extern timer_dev timer14;
#define TIMER_CCMR2_OC3FE (1U << TIMER_CCMR2_OC3FE_BIT)
#define TIMER_CCMR2_IC3PSC (0x3 << 2)
#define TIMER_CCMR2_CC3S 0x3
#define TIMER_CCMR2_CC3S_OUTPUT TIMER_CCMR_CCS_OUTPUT
#define TIMER_CCMR2_CC3S_INPUT_TI1 TIMER_CCMR_CCS_INPUT_TI1
#define TIMER_CCMR2_CC3S_INPUT_TI2 TIMER_CCMR_CCS_INPUT_TI2
#define TIMER_CCMR2_CC3S_INPUT_TRC TIMER_CCMR_CCS_INPUT_TRC
#define TIMER_CCMR2_CC3S_OUTPUT 0x0
#define TIMER_CCMR2_CC3S_INPUT_TI3 0x1
#define TIMER_CCMR2_CC3S_INPUT_TI4 0x2
#define TIMER_CCMR2_CC3S_INPUT_TRC 0x3
/* Capture/compare enable register (CCER) */
@ -564,13 +563,15 @@ typedef enum timer_mode {
* values, the corresponding interrupt is fired. */
TIMER_OUTPUT_COMPARE,
/* TIMER_INPUT_CAPTURE, TODO: In this mode, the timer can measure the
/* TIMER_INPUT_CAPTURE, UNDER DEVELOPMENT: In this mode, the timer can measure the
* pulse lengths of input signals */
/* TIMER_ONE_PULSE, TODO: In this mode, the timer can generate a single
* pulse on a GPIO pin for a specified amount of
* time. */
TIMER_ENCODER, //CARLOS Change
TIMER_INPUT_CAPTURE,// code from @cesco
} timer_mode;
/** Timer channel numbers */
@ -663,6 +664,19 @@ static inline void timer_resume(timer_dev *dev) {
*bb_perip(&(dev->regs).bas->CR1, TIMER_CR1_CEN_BIT) = 1;
}
/**
* @brief Get the status register.
* @param dev Timer device
* @return Status register value (16bits).
*/
static inline uint16 timer_get_status(timer_dev *dev) {
return (dev->regs).gen->SR;
}
static inline void timer_reset_status_bit(timer_dev *dev, uint8 bit) {
*bb_perip(&(dev->regs).gen->SR, bit) = 0;
}
/**
* @brief Returns the timer's counter value.
*
@ -1071,76 +1085,21 @@ static inline void timer_oc_set_mode(timer_dev *dev,
uint32 tmp = *ccmr;
tmp &= ~(0xFF << shift);
tmp |= (mode | flags | TIMER_CCMR_CCS_OUTPUT) << shift;
tmp |= (mode | flags) << shift;
*ccmr = tmp;
}
/*
* Old, erroneous bit definitions from previous releases, kept for
* backwards compatibility:
/**
* Timer output compare modes.
*/
typedef enum timer_ic_input_select {
TIMER_IC_INPUT_DEFAULT = TIMER_CCMR_CCS_INPUT_TI1,
TIMER_IC_INPUT_SWITCH = TIMER_CCMR_CCS_INPUT_TI2,
TIMER_IC_INPUT_TRC = TIMER_CCMR_CCS_INPUT_TRC,
} timer_ic_input_select;
/** Deprecated. Use TIMER_CCMR1_CC4S_OUTPUT instead. */
#define TIMER_CCMR1_CC4S_OUTPUT TIMER_CCMR2_CC4S_OUTPUT
/** Deprecated. Use TIMER_CCMR1_CC4S_INPUT_TI1 instead. */
#define TIMER_CCMR1_CC4S_INPUT_TI1 TIMER_CCMR2_CC4S_INPUT_TI1
/** Deprecated. Use TIMER_CCMR1_CC4S_INPUT_TI2 instead. */
#define TIMER_CCMR1_CC4S_INPUT_TI2 TIMER_CCMR2_CC4S_INPUT_TI2
/** Deprecated. Use TIMER_CCMR1_CC4S_INPUT_TRC instead. */
#define TIMER_CCMR1_CC4S_INPUT_TRC TIMER_CCMR2_CC4S_INPUT_TRC
/** Deprecated. Use TIMER_CCMR2_IC4F instead. */
#define TIMER_CCMR2_IC2F TIMER_CCMR2_IC4F
/** Deprecated. Use TIMER_CCMR2_IC4PSC instead. */
#define TIMER_CCMR2_IC2PSC TIMER_CCMR2_IC4PSC
/** Deprecated. Use TIMER_CCMR2_IC3F instead. */
#define TIMER_CCMR2_IC1F TIMER_CCMR2_IC3F
/** Deprecated. Use TIMER_CCMR2_IC3PSC instead. */
#define TIMER_CCMR2_IC1PSC TIMER_CCMR2_IC3PSC
/** Deprecated. Use TIMER_CCMR1_CC3S_OUTPUT instead. */
#define TIMER_CCMR1_CC3S_OUTPUT TIMER_CCMR2_CC3S_OUTPUT
/** Deprecated. Use TIMER_CCMR1_CC3S_INPUT_TI1 instead. */
#define TIMER_CCMR1_CC3S_INPUT_TI1 TIMER_CCMR2_CC3S_INPUT_TI1
/** Deprecated. Use TIMER_CCMR1_CC3S_INPUT_TI2 instead. */
#define TIMER_CCMR1_CC3S_INPUT_TI2 TIMER_CCMR2_CC3S_INPUT_TI2
/** Deprecated. Use TIMER_CCMR1_CC3S_INPUT_TRC instead. */
#define TIMER_CCMR1_CC3S_INPUT_TRC TIMER_CCMR2_CC3S_INPUT_TRC
extern void input_capture_mode(timer_dev *dev, uint8 channel, timer_ic_input_select input);
/** Deprecated. Use TIMER_DCR_DBL_1_XFER instead. */
#define TIMER_DCR_DBL_1BYTE TIMER_DCR_DBL_1_XFER
/** Deprecated. Use TIMER_DCR_DBL_2_XFER instead. */
#define TIMER_DCR_DBL_2BYTE TIMER_DCR_DBL_2_XFER
/** Deprecated. Use TIMER_DCR_DBL_3_XFER instead. */
#define TIMER_DCR_DBL_3BYTE TIMER_DCR_DBL_3_XFER
/** Deprecated. Use TIMER_DCR_DBL_4_XFER instead. */
#define TIMER_DCR_DBL_4BYTE TIMER_DCR_DBL_4_XFER
/** Deprecated. Use TIMER_DCR_DBL_5_XFER instead. */
#define TIMER_DCR_DBL_5BYTE TIMER_DCR_DBL_5_XFER
/** Deprecated. Use TIMER_DCR_DBL_6_XFER instead. */
#define TIMER_DCR_DBL_6BYTE TIMER_DCR_DBL_6_XFER
/** Deprecated. Use TIMER_DCR_DBL_7_XFER instead. */
#define TIMER_DCR_DBL_7BYTE TIMER_DCR_DBL_7_XFER
/** Deprecated. Use TIMER_DCR_DBL_8_XFER instead. */
#define TIMER_DCR_DBL_8BYTE TIMER_DCR_DBL_8_XFER
/** Deprecated. Use TIMER_DCR_DBL_9_XFER instead. */
#define TIMER_DCR_DBL_9BYTE TIMER_DCR_DBL_9_XFER
/** Deprecated. Use TIMER_DCR_DBL_10_XFER instead. */
#define TIMER_DCR_DBL_10BYTE TIMER_DCR_DBL_10_XFER
/** Deprecated. Use TIMER_DCR_DBL_11_XFER instead. */
#define TIMER_DCR_DBL_11BYTE TIMER_DCR_DBL_11_XFER
/** Deprecated. Use TIMER_DCR_DBL_12_XFER instead. */
#define TIMER_DCR_DBL_12BYTE TIMER_DCR_DBL_12_XFER
/** Deprecated. Use TIMER_DCR_DBL_13_XFER instead. */
#define TIMER_DCR_DBL_13BYTE TIMER_DCR_DBL_13_XFER
/** Deprecated. Use TIMER_DCR_DBL_14_XFER instead. */
#define TIMER_DCR_DBL_14BYTE TIMER_DCR_DBL_14_XFER
/** Deprecated. Use TIMER_DCR_DBL_15_XFER instead. */
#define TIMER_DCR_DBL_15BYTE TIMER_DCR_DBL_15_XFER
/** Deprecated. Use TIMER_DCR_DBL_16_XFER instead. */
#define TIMER_DCR_DBL_16BYTE TIMER_DCR_DBL_16_XFER
/** Deprecated. Use TIMER_DCR_DBL_17_XFER instead. */
#define TIMER_DCR_DBL_17BYTE TIMER_DCR_DBL_17_XFER
/** Deprecated. Use TIMER_DCR_DBL_18_XFER instead. */
#define TIMER_DCR_DBL_18BYTE TIMER_DCR_DBL_18_XFER
#ifdef __cplusplus
} // extern "C"