Simple frequency counter, run without modification on Nucleo board, Input pin PA0, PA1, PB3. Only for STM32F4 series (Tested on Nucleo-F401RE,-F411RE and F446RE)

Dependents:   Frequency_Counter_for_STM32F4xx

see /users/kenjiArai/notebook/frequency-counters/

Revision:
4:3c589d2aad5c
Parent:
3:61bea8bfe404
--- a/freq_counter.cpp	Wed Oct 22 00:35:23 2014 +0000
+++ b/freq_counter.cpp	Mon Jan 13 07:41:08 2020 +0000
@@ -2,104 +2,133 @@
  * mbed Library program
  *      Frequency Counter Hardware relataed program
  *
- * Copyright (c) 2014 Kenji Arai / JH1PJL
- *  http://www.page.sannet.ne.jp/kenjia/index.html
- *  http://mbed.org/users/kenjiArai/
- *      Additional functions and modification
- *      started: October   18th, 2014
- *      Revised: October   22nd, 2014
+ * Copyright (c) 2014,'15,'20 Kenji Arai / JH1PJL
+ *      http://www7b.biglobe.ne.jp/~kenjia/
+ *      https://os.mbed.com/users/kenjiArai/
+ *          Created: October   18th, 2014
+ *          Revised: January   13th, 2020
  *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
- * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
- * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
- * DAMAGES OR OTHER  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
-//-------------------------------------------------------------------------------------------------
-//  Reference program No.1 (see line 104)
-//-------------------------------------------------------------------------------------------------
-//  5MHzOSC
-//      http://developer.mbed.org/users/mio/code/5MHzOSC/
-//  by fuyono sakura
-//      http://developer.mbed.org/users/mio/
 
-//-------------------------------------------------------------------------------------------------
-//  Reference program No.2 (see line 173)
-//-------------------------------------------------------------------------------------------------
-//  fc114
-//      http://developer.mbed.org/users/rutles/code/fc1114/
-//  by Tetsuya Suzuki
-//      http://developer.mbed.org/users/rutles/
+//------------------------------------------------------------------------------
+//  Reference program
+//      5MHzOSC
+//          https://os.mbed.com/users/mio/code/5MHzOSC/
+//      by fuyono sakura
+//          https://os.mbed.com/users/mio/
 
 #include "mbed.h"
 #include "freq_counter.h"
 
-F_COUNTER::F_COUNTER(PinName f_in): _pin(f_in)
+#define WAIT_US     100
+
+F_COUNTER::F_COUNTER(PinName f_in, float gate_time): _pin(f_in)
 {
+    pin_num = f_in;
+    gt = (uint32_t)(gate_time * 1000000.0f);
+    _t.attach_us(callback(this, &F_COUNTER::irq), gt);
+    new_input = false;
     initialize();
 }
 
 void F_COUNTER::initialize(void)
 {
-#if defined(TARGET_LPC1768)
-    LPC_SC->PCONP |= 1 << 22;       // 1)Power up TimerCounter3 (bit23)
-    LPC_PINCON->PINSEL0 |= 3 << 8;  // 2)Set P0[23] to CAP3[0]
-    LPC_TIM2->TCR  = 2;             // 3)Counter Reset (bit1<=1,bit0<=0)
-    LPC_TIM2->CTCR = 1;             // 4)Count on riging edge Cap3[0]
-    LPC_TIM2->CCR  = 0;             // 5)Input Capture Disabled
-    LPC_TIM2->TCR  = 1;             // 6)Counter Start (bit1<=0,bit0<=1)
-#elif defined(TARGET_LPC1114)
-    LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 9);  //TMR32B0 wakeup
-    LPC_IOCON->PIO1_5 |= (1 << 1);  // Set dp14 (pin20) as CT32B0_CAP0
-    LPC_IOCON->PIO1_5 |= (1 << 5);  // Hysteresis enable
-    LPC_TMR32B0->TCR = 2;           // reset
-    LPC_TMR32B0->CTCR  = 1;         // counter mode
-    LPC_TMR32B0->CCR  = 0;          // Input Capture Disable)
-    LPC_TMR32B0->PR  = 0;           // no prescale
-    LPC_TMR32B0->TCR = 1;           // start
-#elif defined(TARGET_NUCLEO_F401RE) || defined(TARGET_NUCLEO_F411RE)
-    // PA0 -> Counter frequency input pin as Timer2 TI1
-    GPIOA->AFR[0] &= 0xfffffff0;
-    GPIOA->AFR[0] |= GPIO_AF1_TIM2;
-    GPIOA->MODER &= ~(GPIO_MODER_MODER0);
-    GPIOA->MODER |= 0x2;
+    if(pin_num <= PA_15) {
+        switch (pin_num) {
+            case PA_0:
+                // PA0 -> Counter frequency input pin as Timer2 TI1
+                GPIOA->AFR[0] &= 0xfffffff0;    // bit 0
+                GPIOA->AFR[0] |= GPIO_AF1_TIM2;
+                GPIOA->MODER &= ~(GPIO_MODER_MODER0);
+                GPIOA->MODER |= 0x2;
+                break;
+            case PA_1:
+                // PA1 -> Counter frequency input pin as Timer2 TI2
+                GPIOA->AFR[0] &= 0xffffff0f;    // bit 1
+                GPIOA->AFR[0] |= GPIO_AF1_TIM2 << (1 * 4);
+                GPIOA->MODER &= ~(GPIO_MODER_MODER1);
+                GPIOA->MODER |= 0x2 << (1 * 2);
+                break;
+            default:
+                return;
+        }
+    } else if (pin_num == PB_3) {
+        // PB3 -> Counter frequency input pin as Timer2 TI2
+        GPIOB->AFR[0] &= 0xffff0fff;    // bit 3
+        GPIOB->AFR[0] |= GPIO_AF1_TIM2 << (3 * 4);
+        GPIOB->MODER &= ~(GPIO_MODER_MODER3);
+        GPIOB->MODER |= 0x2 << (3 * 2);
+    } else {
+        return;
+    }
     // Initialize Timer2(32bit) for an external up counter mode
     RCC->APB1ENR |= ((uint32_t)0x00000001);
-    TIM2->CR1 &= (uint16_t)(~(TIM_CR1_DIR | TIM_CR1_CMS | TIM_CR1_CKD));  // count_up + div by 1
+    // count_up + div by 1
+    TIM2->CR1 &= (uint16_t)(~(TIM_CR1_DIR | TIM_CR1_CMS | TIM_CR1_CKD));
     TIM2->ARR = 0xFFFFFFFF;
     TIM2->PSC = 0x0000;
-    TIM2->CCMR1 &= (uint16_t)~TIM_CCMR1_IC1F;   // input filter
-    TIM2->CCER = TIM_CCER_CC1P;     // positive edge
     TIM2->SMCR &= (uint16_t)~(TIM_SMCR_SMS | TIM_SMCR_TS | TIM_SMCR_ECE);
-    TIM2->SMCR |= (uint16_t)(TIM_TS_TI1FP1 | TIM_SMCR_SMS); // external mode 1
+    if (pin_num == PA_0) {
+        TIM2->CCMR1 &= (uint16_t)~TIM_CCMR1_IC1F;   // input filter
+        TIM2->CCER = TIM_CCER_CC1P;     // positive edge
+        // external mode 1
+        TIM2->SMCR |= (uint16_t)(TIM_TS_TI1FP1 | TIM_SMCR_SMS);
+    } else if ((pin_num == PA_1) || (pin_num == PB_3)) {
+        TIM2->CCMR1 &= (uint16_t)~TIM_CCMR1_IC2F;   // input filter
+        TIM2->CCER = TIM_CCER_CC2P;     // positive edge
+        // external mode 1
+        TIM2->SMCR |= (uint16_t)(TIM_TS_TI2FP2 | TIM_SMCR_SMS);
+    }
     TIM2->CR1 |= TIM_CR1_CEN;   //Enable the TIM Counter
-#else
-#error "No support for this CPU"
-#endif
 }
 
-uint32_t F_COUNTER::read_frequency(float gate_time)
+int32_t F_COUNTER::read_frequency()
 {
-#if defined(TARGET_LPC1768)
-    LPC_TIM2->TCR = 2;             // Reset the counter (bit1<=1,bit0<=0)
-    LPC_TIM2->TCR = 1;             // UnReset counter (bit1<=0,bit0<=1)
-    wait(gate_time);               // Gate time for count
-    freq = LPC_TIM2->TC;           // read counter
-#elif defined(TARGET_LPC1114)
-    LPC_TMR32B0->TCR = 2;           // reset
-    LPC_TMR32B0->TCR = 1;           // start
-    wait(gate_time);                // Gate time for count
-    freq = LPC_TMR32B0->TC;         // read counter
-#elif defined(TARGET_NUCLEO_F401RE) || defined(TARGET_NUCLEO_F411RE)
-    TIM2->CNT = 0;
-    wait(gate_time);                // Gate time for count
-    freq = TIM2->CNT;               // read counter
-#else
-#error "No support for this CPU"
-#endif
-    return freq;
+    int32_t count = gt * 2 / WAIT_US;
+    while (new_input == false) {
+        wait_us(WAIT_US);
+        if (--count < 0) {
+            return -1;
+        }
+    }
+    new_input = false;
+    if ((pin_num == PA_0) || (pin_num == PA_1) || (pin_num == PB_3)) {
+        return freq_raw;
+    } else {
+        return -1;
+    }
 }
 
+void F_COUNTER::set_gate_time(float gate_time)
+{
+    _t.detach();
+    gt = (uint32_t)(gate_time * 1000000.0f);
+    _t.attach_us(callback(this, &F_COUNTER::irq), gt);
+    // delete transient uncorrect data
+    new_input = false;
+    int32_t count = gt / WAIT_US;
+    while (new_input == false) {
+        wait_us(WAIT_US);
+        if (--count < 0) {
+            break;
+        }
+    }
+    new_input = false;
+}
+
+uint32_t F_COUNTER::read_pin()
+{
+    return pin_num;
+}
+
+void F_COUNTER::irq()
+{
+    freq_raw = TIM2->CNT;               // read counter
+    TIM2->CNT = 0;
+    new_input = true;
+}
+
+//------------------------ Reference Program -----------------------------------
 #if 0
 //
 //  CLOCK OUT to PWM1[6] Sample with Freq Counter using Cap2.0
@@ -167,67 +196,3 @@
 }
 
 #endif
-
-#if 0
-
-// fc1114 - Frequency counter with i2c slave.
-// target: LPC1114FN28
-
-#include "mbed.h"
-
-#define I2C_ADRS 0x70
-
-DigitalOut led(dp28);
-I2CSlave slave(dp5, dp27);
-Ticker tick;
-
-volatile uint32_t frq;
-
-void isr_tick()
-{
-    frq = LPC_TMR32B0->TC;
-    LPC_TMR32B0->TC = 0;
-
-    led = !led;
-}
-
-int main()
-{
-    union {
-        char b[4];
-        uint32_t w;
-    } buf;
-    char dummy[4];
-
-    led = 1;
-    tick.attach(&isr_tick, 1);
-
-    LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 9);//TMR32B0 wakeup
-    LPC_IOCON->PIO1_5 |= (1 << 1);// Set PIN14 as CT32B0_CAP0
-    LPC_IOCON->PIO1_5 |= (1 << 5);// Hysteresis enable
-    LPC_TMR32B0->TCR = 2; // reset
-    LPC_TMR32B0->CTCR  = 1; // counter mode
-    LPC_TMR32B0->CCR  = 0; // Input Capture Disable)
-    LPC_TMR32B0->PR  = 0;// no prescale
-    LPC_TMR32B0->TCR = 1; // start
-
-    slave.address(I2C_ADRS << 1);
-
-    while (1) {
-        int i = slave.receive();
-        switch (i) {
-            case I2CSlave::ReadAddressed:
-                buf.w = frq;
-                slave.write(buf.b, 4);
-                break;
-            case I2CSlave::WriteGeneral:
-                slave.read(dummy, 4);
-                break;
-            case I2CSlave::WriteAddressed:
-                slave.read(dummy, 4);
-                break;
-        }
-    }
-}
-
-#endif