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/

Committer:
kenjiArai
Date:
Mon Jan 13 07:41:08 2020 +0000
Revision:
4:3c589d2aad5c
Parent:
3:61bea8bfe404
Modified only for STM32F series (Tested on Nucleo-F401RE,-F411RE and F446RE)

Who changed what in which revision?

UserRevisionLine numberNew contents of line
kenjiArai 0:83661d0d09c0 1 /*
kenjiArai 0:83661d0d09c0 2 * mbed Library program
kenjiArai 0:83661d0d09c0 3 * Frequency Counter Hardware relataed program
kenjiArai 0:83661d0d09c0 4 *
kenjiArai 4:3c589d2aad5c 5 * Copyright (c) 2014,'15,'20 Kenji Arai / JH1PJL
kenjiArai 4:3c589d2aad5c 6 * http://www7b.biglobe.ne.jp/~kenjia/
kenjiArai 4:3c589d2aad5c 7 * https://os.mbed.com/users/kenjiArai/
kenjiArai 4:3c589d2aad5c 8 * Created: October 18th, 2014
kenjiArai 4:3c589d2aad5c 9 * Revised: January 13th, 2020
kenjiArai 0:83661d0d09c0 10 *
kenjiArai 0:83661d0d09c0 11 */
kenjiArai 0:83661d0d09c0 12
kenjiArai 4:3c589d2aad5c 13 //------------------------------------------------------------------------------
kenjiArai 4:3c589d2aad5c 14 // Reference program
kenjiArai 4:3c589d2aad5c 15 // 5MHzOSC
kenjiArai 4:3c589d2aad5c 16 // https://os.mbed.com/users/mio/code/5MHzOSC/
kenjiArai 4:3c589d2aad5c 17 // by fuyono sakura
kenjiArai 4:3c589d2aad5c 18 // https://os.mbed.com/users/mio/
kenjiArai 3:61bea8bfe404 19
kenjiArai 0:83661d0d09c0 20 #include "mbed.h"
kenjiArai 0:83661d0d09c0 21 #include "freq_counter.h"
kenjiArai 0:83661d0d09c0 22
kenjiArai 4:3c589d2aad5c 23 #define WAIT_US 100
kenjiArai 4:3c589d2aad5c 24
kenjiArai 4:3c589d2aad5c 25 F_COUNTER::F_COUNTER(PinName f_in, float gate_time): _pin(f_in)
kenjiArai 0:83661d0d09c0 26 {
kenjiArai 4:3c589d2aad5c 27 pin_num = f_in;
kenjiArai 4:3c589d2aad5c 28 gt = (uint32_t)(gate_time * 1000000.0f);
kenjiArai 4:3c589d2aad5c 29 _t.attach_us(callback(this, &F_COUNTER::irq), gt);
kenjiArai 4:3c589d2aad5c 30 new_input = false;
kenjiArai 0:83661d0d09c0 31 initialize();
kenjiArai 0:83661d0d09c0 32 }
kenjiArai 0:83661d0d09c0 33
kenjiArai 0:83661d0d09c0 34 void F_COUNTER::initialize(void)
kenjiArai 0:83661d0d09c0 35 {
kenjiArai 4:3c589d2aad5c 36 if(pin_num <= PA_15) {
kenjiArai 4:3c589d2aad5c 37 switch (pin_num) {
kenjiArai 4:3c589d2aad5c 38 case PA_0:
kenjiArai 4:3c589d2aad5c 39 // PA0 -> Counter frequency input pin as Timer2 TI1
kenjiArai 4:3c589d2aad5c 40 GPIOA->AFR[0] &= 0xfffffff0; // bit 0
kenjiArai 4:3c589d2aad5c 41 GPIOA->AFR[0] |= GPIO_AF1_TIM2;
kenjiArai 4:3c589d2aad5c 42 GPIOA->MODER &= ~(GPIO_MODER_MODER0);
kenjiArai 4:3c589d2aad5c 43 GPIOA->MODER |= 0x2;
kenjiArai 4:3c589d2aad5c 44 break;
kenjiArai 4:3c589d2aad5c 45 case PA_1:
kenjiArai 4:3c589d2aad5c 46 // PA1 -> Counter frequency input pin as Timer2 TI2
kenjiArai 4:3c589d2aad5c 47 GPIOA->AFR[0] &= 0xffffff0f; // bit 1
kenjiArai 4:3c589d2aad5c 48 GPIOA->AFR[0] |= GPIO_AF1_TIM2 << (1 * 4);
kenjiArai 4:3c589d2aad5c 49 GPIOA->MODER &= ~(GPIO_MODER_MODER1);
kenjiArai 4:3c589d2aad5c 50 GPIOA->MODER |= 0x2 << (1 * 2);
kenjiArai 4:3c589d2aad5c 51 break;
kenjiArai 4:3c589d2aad5c 52 default:
kenjiArai 4:3c589d2aad5c 53 return;
kenjiArai 4:3c589d2aad5c 54 }
kenjiArai 4:3c589d2aad5c 55 } else if (pin_num == PB_3) {
kenjiArai 4:3c589d2aad5c 56 // PB3 -> Counter frequency input pin as Timer2 TI2
kenjiArai 4:3c589d2aad5c 57 GPIOB->AFR[0] &= 0xffff0fff; // bit 3
kenjiArai 4:3c589d2aad5c 58 GPIOB->AFR[0] |= GPIO_AF1_TIM2 << (3 * 4);
kenjiArai 4:3c589d2aad5c 59 GPIOB->MODER &= ~(GPIO_MODER_MODER3);
kenjiArai 4:3c589d2aad5c 60 GPIOB->MODER |= 0x2 << (3 * 2);
kenjiArai 4:3c589d2aad5c 61 } else {
kenjiArai 4:3c589d2aad5c 62 return;
kenjiArai 4:3c589d2aad5c 63 }
kenjiArai 1:fd2e1c853ab6 64 // Initialize Timer2(32bit) for an external up counter mode
kenjiArai 1:fd2e1c853ab6 65 RCC->APB1ENR |= ((uint32_t)0x00000001);
kenjiArai 4:3c589d2aad5c 66 // count_up + div by 1
kenjiArai 4:3c589d2aad5c 67 TIM2->CR1 &= (uint16_t)(~(TIM_CR1_DIR | TIM_CR1_CMS | TIM_CR1_CKD));
kenjiArai 1:fd2e1c853ab6 68 TIM2->ARR = 0xFFFFFFFF;
kenjiArai 1:fd2e1c853ab6 69 TIM2->PSC = 0x0000;
kenjiArai 1:fd2e1c853ab6 70 TIM2->SMCR &= (uint16_t)~(TIM_SMCR_SMS | TIM_SMCR_TS | TIM_SMCR_ECE);
kenjiArai 4:3c589d2aad5c 71 if (pin_num == PA_0) {
kenjiArai 4:3c589d2aad5c 72 TIM2->CCMR1 &= (uint16_t)~TIM_CCMR1_IC1F; // input filter
kenjiArai 4:3c589d2aad5c 73 TIM2->CCER = TIM_CCER_CC1P; // positive edge
kenjiArai 4:3c589d2aad5c 74 // external mode 1
kenjiArai 4:3c589d2aad5c 75 TIM2->SMCR |= (uint16_t)(TIM_TS_TI1FP1 | TIM_SMCR_SMS);
kenjiArai 4:3c589d2aad5c 76 } else if ((pin_num == PA_1) || (pin_num == PB_3)) {
kenjiArai 4:3c589d2aad5c 77 TIM2->CCMR1 &= (uint16_t)~TIM_CCMR1_IC2F; // input filter
kenjiArai 4:3c589d2aad5c 78 TIM2->CCER = TIM_CCER_CC2P; // positive edge
kenjiArai 4:3c589d2aad5c 79 // external mode 1
kenjiArai 4:3c589d2aad5c 80 TIM2->SMCR |= (uint16_t)(TIM_TS_TI2FP2 | TIM_SMCR_SMS);
kenjiArai 4:3c589d2aad5c 81 }
kenjiArai 1:fd2e1c853ab6 82 TIM2->CR1 |= TIM_CR1_CEN; //Enable the TIM Counter
kenjiArai 0:83661d0d09c0 83 }
kenjiArai 0:83661d0d09c0 84
kenjiArai 4:3c589d2aad5c 85 int32_t F_COUNTER::read_frequency()
kenjiArai 0:83661d0d09c0 86 {
kenjiArai 4:3c589d2aad5c 87 int32_t count = gt * 2 / WAIT_US;
kenjiArai 4:3c589d2aad5c 88 while (new_input == false) {
kenjiArai 4:3c589d2aad5c 89 wait_us(WAIT_US);
kenjiArai 4:3c589d2aad5c 90 if (--count < 0) {
kenjiArai 4:3c589d2aad5c 91 return -1;
kenjiArai 4:3c589d2aad5c 92 }
kenjiArai 4:3c589d2aad5c 93 }
kenjiArai 4:3c589d2aad5c 94 new_input = false;
kenjiArai 4:3c589d2aad5c 95 if ((pin_num == PA_0) || (pin_num == PA_1) || (pin_num == PB_3)) {
kenjiArai 4:3c589d2aad5c 96 return freq_raw;
kenjiArai 4:3c589d2aad5c 97 } else {
kenjiArai 4:3c589d2aad5c 98 return -1;
kenjiArai 4:3c589d2aad5c 99 }
kenjiArai 0:83661d0d09c0 100 }
kenjiArai 0:83661d0d09c0 101
kenjiArai 4:3c589d2aad5c 102 void F_COUNTER::set_gate_time(float gate_time)
kenjiArai 4:3c589d2aad5c 103 {
kenjiArai 4:3c589d2aad5c 104 _t.detach();
kenjiArai 4:3c589d2aad5c 105 gt = (uint32_t)(gate_time * 1000000.0f);
kenjiArai 4:3c589d2aad5c 106 _t.attach_us(callback(this, &F_COUNTER::irq), gt);
kenjiArai 4:3c589d2aad5c 107 // delete transient uncorrect data
kenjiArai 4:3c589d2aad5c 108 new_input = false;
kenjiArai 4:3c589d2aad5c 109 int32_t count = gt / WAIT_US;
kenjiArai 4:3c589d2aad5c 110 while (new_input == false) {
kenjiArai 4:3c589d2aad5c 111 wait_us(WAIT_US);
kenjiArai 4:3c589d2aad5c 112 if (--count < 0) {
kenjiArai 4:3c589d2aad5c 113 break;
kenjiArai 4:3c589d2aad5c 114 }
kenjiArai 4:3c589d2aad5c 115 }
kenjiArai 4:3c589d2aad5c 116 new_input = false;
kenjiArai 4:3c589d2aad5c 117 }
kenjiArai 4:3c589d2aad5c 118
kenjiArai 4:3c589d2aad5c 119 uint32_t F_COUNTER::read_pin()
kenjiArai 4:3c589d2aad5c 120 {
kenjiArai 4:3c589d2aad5c 121 return pin_num;
kenjiArai 4:3c589d2aad5c 122 }
kenjiArai 4:3c589d2aad5c 123
kenjiArai 4:3c589d2aad5c 124 void F_COUNTER::irq()
kenjiArai 4:3c589d2aad5c 125 {
kenjiArai 4:3c589d2aad5c 126 freq_raw = TIM2->CNT; // read counter
kenjiArai 4:3c589d2aad5c 127 TIM2->CNT = 0;
kenjiArai 4:3c589d2aad5c 128 new_input = true;
kenjiArai 4:3c589d2aad5c 129 }
kenjiArai 4:3c589d2aad5c 130
kenjiArai 4:3c589d2aad5c 131 //------------------------ Reference Program -----------------------------------
kenjiArai 0:83661d0d09c0 132 #if 0
kenjiArai 0:83661d0d09c0 133 //
kenjiArai 0:83661d0d09c0 134 // CLOCK OUT to PWM1[6] Sample with Freq Counter using Cap2.0
kenjiArai 0:83661d0d09c0 135 // For LPC1768-mbed
kenjiArai 0:83661d0d09c0 136 //
kenjiArai 0:83661d0d09c0 137 // Reference: 5MHz Clock Out Code and Comment - http://mbed.org/forum/mbed/topic/733/
kenjiArai 0:83661d0d09c0 138 //
kenjiArai 0:83661d0d09c0 139 // !! To Self Measurement Output Clock, Connect p21 <-> p30 with jumper wire.
kenjiArai 0:83661d0d09c0 140 // 2013.6.18 : Wrong comment about MR6 and Duty fix.
kenjiArai 0:83661d0d09c0 141 //
kenjiArai 0:83661d0d09c0 142
kenjiArai 0:83661d0d09c0 143 #include "mbed.h"
kenjiArai 0:83661d0d09c0 144
kenjiArai 0:83661d0d09c0 145 PwmOut fmclck(p21); // for RESERVE pin21 as PWM1[6]
kenjiArai 0:83661d0d09c0 146 DigitalIn clkin(p30); // for RESERVE pin30 as CAP2[0]
kenjiArai 0:83661d0d09c0 147
kenjiArai 0:83661d0d09c0 148 // Reset Counter and Count Start
kenjiArai 0:83661d0d09c0 149 void P30_RESET_CTR(void)
kenjiArai 0:83661d0d09c0 150 {
kenjiArai 0:83661d0d09c0 151 LPC_TIM2->TCR = 2; // Reset the counter (bit1<=1,bit0<=0)
kenjiArai 0:83661d0d09c0 152 LPC_TIM2->TCR = 1; // UnReset counter (bit1<=0,bit0<=1)
kenjiArai 0:83661d0d09c0 153 }
kenjiArai 0:83661d0d09c0 154
kenjiArai 0:83661d0d09c0 155 // Get Counter Value
kenjiArai 0:83661d0d09c0 156 int P30_GET_CTR(void)
kenjiArai 0:83661d0d09c0 157 {
kenjiArai 0:83661d0d09c0 158 return LPC_TIM2->TC; // Read the counter value
kenjiArai 0:83661d0d09c0 159 }
kenjiArai 0:83661d0d09c0 160
kenjiArai 0:83661d0d09c0 161 // Setting p30 to Cap2.0
kenjiArai 0:83661d0d09c0 162 void P30_INIT_CTR(void)
kenjiArai 0:83661d0d09c0 163 {
kenjiArai 0:83661d0d09c0 164 LPC_SC->PCONP |= 1 << 22; // 1)Power up TimerCounter2 (bit22)
kenjiArai 0:83661d0d09c0 165 LPC_PINCON->PINSEL0 |= 3 << 8; // 2)Set P0[4] to CAP2[0]
kenjiArai 0:83661d0d09c0 166 LPC_TIM2->TCR = 2; // 3)Counter Reset (bit1<=1,bit0<=0)
kenjiArai 0:83661d0d09c0 167 LPC_TIM2->CTCR = 1; // 4)Count on riging edge Cap2[0]
kenjiArai 0:83661d0d09c0 168 LPC_TIM2->CCR = 0; // 5)Input Capture Disabled
kenjiArai 0:83661d0d09c0 169 LPC_TIM2->TCR = 1; // 6)Counter Start (bit1<=0,bit0<=1)
kenjiArai 0:83661d0d09c0 170 }
kenjiArai 0:83661d0d09c0 171
kenjiArai 0:83661d0d09c0 172 // Clock Output From pin21(PWM6)
kenjiArai 0:83661d0d09c0 173 // Set Clock Freq with div.
kenjiArai 0:83661d0d09c0 174 // if mbed is running at 96MHz, div is set 96 to Get 1MHz.
kenjiArai 0:83661d0d09c0 175 void PWM6_SETCLK(int div)
kenjiArai 0:83661d0d09c0 176 {
kenjiArai 0:83661d0d09c0 177 LPC_PWM1->TCR = (1 << 1); // 1)Reset counter, disable PWM
kenjiArai 0:83661d0d09c0 178 LPC_SC->PCLKSEL0 &= ~(0x3 << 12);
kenjiArai 0:83661d0d09c0 179 LPC_SC->PCLKSEL0 |= (1 << 12); // 2)Set peripheral clock divider to /1, i.e. system clock
kenjiArai 0:83661d0d09c0 180 LPC_PWM1->MR0 = div - 1; // 3)Match Register 0 is shared period counter for all PWM1
kenjiArai 0:83661d0d09c0 181 LPC_PWM1->MR6 = (div + 1)>> 1; //
kenjiArai 0:83661d0d09c0 182 LPC_PWM1->LER |= 1; // 4)Start updating at next period start
kenjiArai 0:83661d0d09c0 183 LPC_PWM1->TCR = (1 << 0) || (1 << 3); // 5)Enable counter and PWM
kenjiArai 0:83661d0d09c0 184 }
kenjiArai 0:83661d0d09c0 185
kenjiArai 0:83661d0d09c0 186 int main()
kenjiArai 0:83661d0d09c0 187 {
kenjiArai 0:83661d0d09c0 188 PWM6_SETCLK(19) ; // Outout mbed's "PWM6" pin to 96MHZ/19 = 5.052MHz (Approx)
kenjiArai 0:83661d0d09c0 189 // PWM6_SETCLK(96) ; // Outout mbed's "PWM6" pin to 96MHZ/96 = 1.000MHz (Approx)
kenjiArai 0:83661d0d09c0 190 P30_INIT_CTR();
kenjiArai 0:83661d0d09c0 191 while(1) {
kenjiArai 0:83661d0d09c0 192 P30_RESET_CTR();
kenjiArai 0:83661d0d09c0 193 wait(1.0); // Gate time for count
kenjiArai 0:83661d0d09c0 194 printf("pin30 Freq = %d (Hz)\r\n",P30_GET_CTR());
kenjiArai 0:83661d0d09c0 195 }
kenjiArai 0:83661d0d09c0 196 }
kenjiArai 0:83661d0d09c0 197
kenjiArai 0:83661d0d09c0 198 #endif