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/

freq_counter.cpp

Committer:
kenjiArai
Date:
2020-01-13
Revision:
4:3c589d2aad5c
Parent:
3:61bea8bfe404

File content as of revision 4:3c589d2aad5c:

/*
 * mbed Library program
 *      Frequency Counter Hardware relataed program
 *
 * 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
 *
 */

//------------------------------------------------------------------------------
//  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"

#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(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);
    // 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->SMCR &= (uint16_t)~(TIM_SMCR_SMS | TIM_SMCR_TS | TIM_SMCR_ECE);
    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
}

int32_t F_COUNTER::read_frequency()
{
    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
//  For LPC1768-mbed
//
//  Reference: 5MHz Clock Out Code and Comment - http://mbed.org/forum/mbed/topic/733/
//
//  !! To Self Measurement Output Clock, Connect p21 <-> p30 with jumper wire.
//  2013.6.18 : Wrong comment about MR6 and Duty fix.
//

#include "mbed.h"

PwmOut fmclck(p21);     // for RESERVE pin21 as PWM1[6]
DigitalIn clkin(p30);   // for RESERVE pin30 as CAP2[0]

// Reset Counter and Count Start
void P30_RESET_CTR(void)
{
    LPC_TIM2->TCR = 2;             // Reset the counter (bit1<=1,bit0<=0)
    LPC_TIM2->TCR = 1;             // UnReset counter (bit1<=0,bit0<=1)
}

// Get Counter Value
int P30_GET_CTR(void)
{
    return LPC_TIM2->TC; // Read the counter value
}

// Setting p30 to Cap2.0
void P30_INIT_CTR(void)
{
    LPC_SC->PCONP |= 1 << 22;               // 1)Power up TimerCounter2 (bit22)
    LPC_PINCON->PINSEL0 |= 3 << 8;          // 2)Set P0[4] to CAP2[0]
    LPC_TIM2->TCR = 2;                          // 3)Counter Reset (bit1<=1,bit0<=0)
    LPC_TIM2->CTCR = 1;                     // 4)Count on riging edge Cap2[0]
    LPC_TIM2->CCR = 0;                                          // 5)Input Capture Disabled
    LPC_TIM2->TCR = 1;                          // 6)Counter Start (bit1<=0,bit0<=1)
}

// Clock Output From pin21(PWM6)
// Set Clock Freq with div.
// if mbed is running at 96MHz, div is set 96 to Get 1MHz.
void PWM6_SETCLK(int div)
{
    LPC_PWM1->TCR = (1 << 1);               // 1)Reset counter, disable PWM
    LPC_SC->PCLKSEL0 &= ~(0x3 << 12);
    LPC_SC->PCLKSEL0 |= (1 << 12);          // 2)Set peripheral clock divider to /1, i.e. system clock
    LPC_PWM1->MR0 = div - 1;                // 3)Match Register 0 is shared period counter for all PWM1
    LPC_PWM1->MR6 = (div + 1)>> 1;          //
    LPC_PWM1->LER |= 1;                     // 4)Start updating at next period start
    LPC_PWM1->TCR = (1 << 0) || (1 << 3);   // 5)Enable counter and PWM
}

int main()
{
    PWM6_SETCLK(19) ; // Outout mbed's "PWM6" pin to 96MHZ/19 = 5.052MHz (Approx)
    // PWM6_SETCLK(96) ; // Outout mbed's "PWM6" pin to 96MHZ/96 = 1.000MHz (Approx)
    P30_INIT_CTR();
    while(1) {
        P30_RESET_CTR();
        wait(1.0); // Gate time for count
        printf("pin30 Freq = %d (Hz)\r\n",P30_GET_CTR());
    }
}

#endif