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@4:3c589d2aad5c, 2020-01-13 (annotated)
- 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?
User | Revision | Line number | New 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 |