Reciprocal Frequency counter only for STM32F401、F411 and F466. Reciprocal Mode -> Pulse width measurement
Dependents: Frequency_Counter_Recipro_for_STM32F4xx
fc_recipro.cpp
- Committer:
- kenjiArai
- Date:
- 2020-01-19
- Revision:
- 8:c9ed197ce270
- Parent:
- 7:7fdff925855e
File content as of revision 8:c9ed197ce270:
/* * mbed Library / Frequency Counter / Recipro type * Frequency Counter program * Only for Nucleo-F401RE,-F411RE,-F446RE * * Copyright (c) 2014,'15,'16,'20 Kenji Arai / JH1PJL * http://www7b.biglobe.ne.jp/~kenjia/ * https://os.mbed.com/users/kenjiArai/ * Started: October 18th, 2014 * Revised: January 19th, 2020 */ #include "fc_recipro.h" #if (MBED_MAJOR_VERSION == 2) # define WAIT(x) wait_ms(x) #elif (MBED_MAJOR_VERSION == 5) # define WAIT(x) ThisThread::sleep_for(x) #endif #if DEBUG #define PRINTF(...) printf(__VA_ARGS__) #define SET0 {tstp0=1;} #define CLR0 {tstp0=0;} #define SET1 {tstp1=1;} #define CLR1 {tstp1=0;} #define SET2 {tstp2=1;} #define CLR2 {tstp2=0;} #else #define PRINTF(...) {;} #define SET0 {;} #define CLR0 {;} #define SET1 {;} #define CLR1 {;} #define SET2 {;} #define CLR2 {;} #endif typedef union { struct { int64_t f_64bit_dt; // not uint but int }; struct { uint32_t freq_dt; int32_t f_sw_dt; // not uint but int }; } freq_one; namespace Frequency_counter { #if DEBUG // Check interrupt handler processing time DigitalOut tstp0(D13, 1); DigitalOut tstp1(D12, 1); DigitalOut tstp2(D11, 1); #endif // TIM2 IC (Reciprocal) + OverFlow static int32_t sw_ovrflw_tim2; static uint8_t rise_cnt; static uint8_t fall_cnt; // buffer for captured data freq_one captured_dt; // frequency data in pack (interrupt) int64_t rise_buf[2]; int64_t fall_buf[2]; uint32_t rise_pointer; uint32_t fall_pointer; //------------------------------------------------------------------------------ // Frequency Counter Library //------------------------------------------------------------------------------ FRQ_CUNTR::FRQ_CUNTR(PinName pin) : _input_pin(pin) { rise_pointer = 0; fall_pointer = 0; initialize_TIM2(); // Use for reciprocal } //------------------------------------------------------------------------------ // Initialize TIM2 //------------------------------------------------------------------------------ // IC1->PA0 for Reciprocal frequency counting mode (Interrupt) ->Rising Edge // IC2->PA1 for Reciprocal frequency counting mode (Interrupt) ->Falling Edge void FRQ_CUNTR::initialize_TIM2(void) { // Initialize Timer2(32bit) for an internal(90MHz/F446) up counter mode RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; // count_up + div by 1 TIM2->CR1 &= (uint16_t)(~(TIM_CR1_DIR | TIM_CR1_CMS | TIM_CR1_CKD)); // only counter overflow for interrupt TIM2->CR1 |= (uint16_t)TIM_CR1_URS; // Up counter uses from 0 to max(32bit) TIM2->ARR = 0xffffffff; TIM2->PSC = 0x0000; // 1/1 TIM2->CCER = 0; // Reset all // PA0 -> Input Capture pin as Timer2 IC1 for Reciprocal GPIOA->AFR[0] &= 0xfffffff0; GPIOA->AFR[0] |= GPIO_AF1_TIM2 << 0; // 0bit x 4 GPIOA->MODER &= ~(GPIO_MODER_MODER0); // AF GPIOA->MODER |= GPIO_MODER_MODER0_1; // alternate function mode GPIOA->PUPDR &= ~(GPIO_PUPDR_PUPDR0); // PU GPIOA->PUPDR |= GPIO_PUPDR_PUPDR0_0; // Pull-up mode // Initialize Timer2 IC1 // input filter + input select TIM2->CCMR1 &= ~(TIM_CCMR1_IC1F | TIM_CCMR1_CC1S); TIM2->CCMR1 |= (TIM_CCMR1_CC1S_0 + TIM_CCMR1_IC1F_0); // filter -> N=2 // Rising Edge <------------------------------ TIM2->CCER &= (uint16_t)~(TIM_CCER_CC1P | TIM_CCER_CC1NP); // enable capture + Rising Edge(0) TIM2->CCER |= (uint16_t)TIM_CCER_CC1E; // PA1 -> Input Capture pin as Timer2 IC2 GPIOA->AFR[0] &= 0xffffff0f; GPIOA->AFR[0] |= GPIO_AF1_TIM2 << 4; // 1bit x 4 GPIOA->MODER &= ~(GPIO_MODER_MODER1); // AF GPIOA->MODER |= GPIO_MODER_MODER1_1; // alternate function mode GPIOA->PUPDR &= ~(GPIO_PUPDR_PUPDR1); // PU GPIOA->PUPDR |= GPIO_PUPDR_PUPDR1_0; // Pull-up mode // Initialize Timer2 IC2 // input filter + input select TIM2->CCMR1 &= ~(TIM_CCMR1_IC2F | TIM_CCMR1_CC2S); TIM2->CCMR1 |= (TIM_CCMR1_CC2S_0 + TIM_CCMR1_IC2F_0); // filter -> N=2 // Falling Edge <------------------------------ TIM2->CCER &= (uint16_t)~(TIM_CCER_CC2P | TIM_CCER_CC2NP); // enable capture + Falling Edge(1) TIM2->CCER |= (uint16_t)TIM_CCER_CC2E | TIM_CCER_CC2P; // Only for Debug purpose // PA PRINTF("\r\n// Timer2(32bit) for an internal up counter mode\r\n"); PRINTF("// Set GPIO for Timer2\r\n"); PRINTF("// PA0 -> Input Capture pin as Timer2 CH1/TI1\r\n"); PRINTF("// PA1 -> Input Capture pin as Timer2 CH2/TI2\r\n"); PRINTF("GPIOA->AFRL 0x%08x:0x%08x\r\n",&GPIOA->AFR[0], GPIOA->AFR[0]); PRINTF("GPIOA->AFRH 0x%08x:0x%08x\r\n",&GPIOA->AFR[1], GPIOA->AFR[1]); PRINTF("GPIOA->MODER 0x%08x:0x%08x\r\n",&GPIOA->MODER, GPIOA->MODER); PRINTF("GPIOA->PUPDR 0x%08x:0x%08x\r\n",&GPIOA->PUPDR, GPIOA->PUPDR); // TIM2 PRINTF("// PA0 -> Timer2 IC1\r\n"); PRINTF("// PA1 -> Timer2 IC2\r\n"); PRINTF("TIM2->CR1 0x%08x:0x%08x\r\n",&TIM2->CR1, TIM2->CR1); PRINTF("TIM2->CR2 0x%08x:0x%08x\r\n",&TIM2->CR2, TIM2->CR2); PRINTF("TIM2->ARR 0x%08x:0x%08x\r\n",&TIM2->ARR, TIM2->ARR); PRINTF("TIM2->PSC 0x%08x:0x%08x\r\n",&TIM2->PSC, TIM2->PSC); PRINTF("TIM2->CCMR1 0x%08x:0x%08x\r\n",&TIM2->CCMR1, TIM2->CCMR1); PRINTF("TIM2->CCMR2 0x%08x:0x%08x\r\n",&TIM2->CCMR2, TIM2->CCMR2); PRINTF("TIM2->CCER 0x%08x:0x%08x\r\n",&TIM2->CCER, TIM2->CCER); PRINTF("TIM2->SMCR 0x%08x:0x%08x\r\n",&TIM2->SMCR, TIM2->SMCR); // Timer2 Overflow TIM2->DIER = 0; // Disable all interrupt sw_ovrflw_tim2 = 0; TIM2->CCR1 = 0; TIM2->CCR2 = 0; uint32_t dummy = TIM2->CCR1; dummy = TIM2->CCR1; dummy = TIM2->CCR2; dummy = TIM2->CCR2; TIM2->CNT = 0; TIM2->SR = 0; // clear all IC/OC flag // set clock source then enable TIM2->SMCR = 0; // Internal clock TIM2->CR1 |= (uint16_t)TIM_CR1_CEN; // Enable the TIM Counter // interrupt NVIC_SetVector(TIM2_IRQn, (uint32_t)irq_ic_TIM2); NVIC_ClearPendingIRQ(TIM2_IRQn); NVIC_EnableIRQ(TIM2_IRQn); PRINTF("TIM2->DIER 0x%08x:0x%08x\r\n\r\n",&TIM2->DIER, TIM2->DIER); } //------------------------------------------------------------------------------ // Reciprocal measuremt //------------------------------------------------------------------------------ void FRQ_CUNTR::start_action(void) { __disable_irq(); TIM2->SR &= ~(TIM_SR_CC1IF | TIM_SR_CC2IF); // clear IC flag TIM2->DIER |= TIM_DIER_CC1IE | TIM_DIER_CC2IE; // Enable IC1+IC2 __enable_irq(); } void FRQ_CUNTR::stop_action(void) { __disable_irq(); TIM2->SR &= ~(TIM_SR_CC1IF | TIM_SR_CC2IF); // clear IC flag __enable_irq(); } void FRQ_CUNTR::recipro_start_measurement() { SystemCoreClockUpdate(); _base_clock = (float)read_base_clock_frequency(); rise_cnt = 0; fall_cnt = 0; _data_ready = false; rise_buf[0] = 0; rise_buf[1] = 0; fall_buf[0] = 0; fall_buf[1] = 0; start_action(); _t.reset(); _t.start(); } void FRQ_CUNTR::recipro_stop_measurement() { _t.reset(); _t.stop(); stop_action(); } bool FRQ_CUNTR::recipro_check_status(Recipro_status_TypeDef *status) { freq_one _temp; bool _ready = false; _data_buf[0] = rise_buf[0]; _data_buf[1] = rise_buf[1]; _data_buf[2] = fall_buf[0]; _data_buf[3] = fall_buf[1]; uint8_t sum = 0; if (_data_buf[0] == 0) { ++sum;} if (_data_buf[1] == 0) { ++sum;} if (_data_buf[2] == 0) { ++sum;} if (_data_buf[3] == 0) { ++sum;} if (sum != 4) { _ready = true; // change order if (_data_buf[0] > _data_buf[1]){ _temp.f_64bit_dt = _data_buf[0]; _data_buf[0] = _data_buf[1]; _data_buf[1] = _temp.f_64bit_dt; } _tp0 = _data_buf[1] - _data_buf[0]; if (_tp0 < 0) { _tp0 = 0; } if (_data_buf[2] > _data_buf[3]){ _temp.f_64bit_dt = _data_buf[2]; _data_buf[2] = _data_buf[3]; _data_buf[3] = _temp.f_64bit_dt; } _tp1 = _data_buf[3] - _data_buf[2]; if (_tp1 < 0) { _tp1 = 0; } // calculate diff if (_data_buf[3] > _data_buf[1]) { //type A _tp2 = _data_buf[2] - _data_buf[0]; _tp3 = _data_buf[1] - _data_buf[2]; } else { //type B _tp2 = _data_buf[3] - _data_buf[0]; _tp3 = _data_buf[0] - _data_buf[2]; } if (_tp2 < 0) { _tp2 = 0; } if (_tp3 < 0) { _tp3 = 0; } } PRINTF("rise_buf[0] = %.0f\r\n", (float)rise_buf[0]); PRINTF("rise_buf[1] = %.0f\r\n", (float)rise_buf[1]); PRINTF("fall_buf[0] = %.0f\r\n", (float)fall_buf[0]); PRINTF("fall_buf[1] = %.0f\r\n", (float)fall_buf[1]); PRINTF("data_buf0[0]= %.0f\r\n", (float)_data_buf[0]); PRINTF("data_buf0[1]= %.0f\r\n", (float)_data_buf[1]); PRINTF("data_buf1[0]= %.0f\r\n", (float)_data_buf[2]); PRINTF("data_buf1[1]= %.0f\r\n", (float)_data_buf[3]); PRINTF("tp0= %.0f\r\n", (float)_tp0); PRINTF("tp1= %.0f\r\n", (float)_tp1); PRINTF("tp2= %.0f\r\n", (float)_tp2); PRINTF("tp3= %.0f\r\n", (float)_tp3); if (_ready == true) { _freq_rise2rise = _base_clock / (float)_tp0; _freq_fall2fall = _base_clock / (float)_tp1; _time_us_rise2fall = (float)_tp2 / _base_clock * 1.0e3; _time_us_fall2rise = (float)_tp3 / _base_clock * 1.0e3; _data_ready = true; PRINTF("freq_rise2rise= %f [Hz]\r\n", _freq_rise2rise); PRINTF("freq_fall2fall= %f [Hz]\r\n", _freq_fall2fall); PRINTF("time_us_rise2fall= %f [mS]\r\n", _time_us_rise2fall); PRINTF("time_us_fall2rise= %f [mS]\r\n", _time_us_fall2rise); } status->rise_cnt = rise_cnt; status->fall_cnt = fall_cnt; status->input_level = _input_pin.read(); status->passed_time = (float)_t.read_us() / 1.0e6; return _data_ready; } void FRQ_CUNTR::recipro_get_result(Recipro_result_TypeDef *fq) { fq->freq_rise2rise = _freq_rise2rise; fq->freq_fall2fall = _freq_fall2fall; fq->time_us_rise2fall = _time_us_rise2fall; fq->time_us_fall2rise = _time_us_fall2rise; } void FRQ_CUNTR::recipro_get_raw_data(int64_t *buf) { int64_t *pointer = buf; *pointer++ = rise_buf[0]; *pointer++ = fall_buf[0]; *pointer++ = rise_buf[1]; *pointer++ = fall_buf[1]; pointer = buf; for (uint32_t i = 0; i < 4; i++) { float dt = (float)*pointer++; PRINTF("%2d = %12.0f \r\n", i, dt); } } //------------------------------------------------------------------------------ // Interrupt Handlers //------------------------------------------------------------------------------ // Reciprocal data (TIM2 IC1+IC2) void irq_ic_TIM2(void) { // IC1 (for reciprocal measurement / Rising edge) uint32_t reg = TIM2->SR; if (reg & TIM_SR_CC1IF) { SET0; TIM2->SR &= ~TIM_SR_CC1IF; // clear IC flag captured_dt.freq_dt = TIM2->CCR1; captured_dt.f_sw_dt = sw_ovrflw_tim2; rise_buf[rise_pointer % 2] = captured_dt.f_64bit_dt; ++rise_pointer; ++rise_cnt; CLR0; } // IC2 (for reciprocal measurement / Falling edge) if (reg & TIM_SR_CC2IF) { SET1; TIM2->SR &= ~TIM_SR_CC2IF; // clear IC flag captured_dt.freq_dt = TIM2->CCR2; captured_dt.f_sw_dt = sw_ovrflw_tim2; fall_buf[fall_pointer % 2] = captured_dt.f_64bit_dt; ++fall_pointer; ++fall_cnt; CLR1; } // TIM2 overflow if (reg & TIM_SR_UIF) { // 32bit counter overflow SET2; TIM2->SR &= ~TIM_SR_UIF; // clear UIF(overflow) flag ++sw_ovrflw_tim2; CLR2 } } //------------------------------------------------------------------------------ // Frequency check for test & debug purpose //------------------------------------------------------------------------------ // Read TIM2 Clock frequency uint32_t FRQ_CUNTR::read_base_clock_frequency(void) { TIM2->CNT = 0; wait_us(1000000); // Gate time = 1seconds uint32_t freq = TIM2->CNT; // read counter PRINTF("Clock Frequency= %10d, gate= %4.2f [Sec]\r\n", freq); return freq; // return counter data } // uint32_t FRQ_CUNTR::read_tm2_overflow(void) { return sw_ovrflw_tim2; } } // Frequency_counter