Frequency counter library only for DISCO-F746NG & NucleoF411RE +F446RE
Dependents: FreqCntr_GPS1PPS_F746F4xx_w_recipro Freq_Cntr_GPS1PPS_F746NG_GUI
Fork of Frq_cuntr_full by
fc_hw_f411.h
- Committer:
- kenjiArai
- Date:
- 2016-11-16
- Revision:
- 6:be7123d400ae
- Parent:
- 5:783b039f9119
File content as of revision 6:be7123d400ae:
/* * mbed Library / Frequency Counter using GPS 1PPS gate pulse * Frequency Counter Hardware relataed program * Only for ST Nucleo-F411RE+F446RE * * Re-started: October 5th, 2016 Change board -> DISCO-F746NG * Re-started: October 17th, 2016 Back to F411 * Revised: November 8th, 2016 * */ #if defined(TARGET_NUCLEO_F411RE) || defined(TARGET_NUCLEO_F446RE) // Following ring buffers are very big!! 1024 x 8(bytes) x 2(buff) = 16KB RingBuff<uint64_t> fdt_buffer(1024); // RinBuffer for TIM1+3 freq_one fdt; // frequency data in pack (interrupt) RingBuff<uint64_t> onepps_buf(1024); // RinBuffer for TIM2 freq_one onepps_dt; // frequency data in pack (interrupt) //------------------------------------------------------------------------------ // Initialize TIM1+3 and TIM2 //------------------------------------------------------------------------------ // Initialize TIM1 & TIM3 as 32bit counter (TIM1(Low 16bit) + TIM3(High 16bit)) // TIM1 clock input is unkown freq.(measuring freq.) and TIM3 is slave counter // 1PPS gate signal connected both TIM1 IC2, TIM3 IC3 (& TIM2 IC2) void FRQ_CUNTR::initialize_TIMxPy(void) { // Timer1 input max freq.= 48MHz (@SystemCoreClock = 96MHz) // PA8 -> Unkown frequency input pin as Timer1 CH1/TI1 RCC->AHB1ENR |= (RCC_AHB1ENR_GPIOAEN); GPIOA->AFR[1] &= 0xfffffff0; GPIOA->AFR[1] |= GPIO_AF1_TIM1 << 0; // (8-8)bit x 4 GPIOA->MODER &= ~(GPIO_MODER_MODER8); // AF GPIOA->MODER |= GPIO_MODER_MODER8_1; // alternate function mode GPIOA->PUPDR &= ~(GPIO_PUPDR_PUPDR8); // PU GPIOA->PUPDR |= GPIO_PUPDR_PUPDR8_0; // Pull-up mode // Initialize Timer1(16bit) for an external up counter mode RCC->APB2ENR |= RCC_APB2ENR_TIM1EN; // count_up + div by 1 TIM1->CR1 &= (uint16_t)(~(TIM_CR1_DIR | TIM_CR1_CMS | TIM_CR1_CKD)); // update request only by overflow TIM1->CR1 |= (uint16_t)TIM_CR1_URS; TIM1->ARR = 0xffff; // Use 16bit full TIM1->CCER = 0; // Reset all // input filter + input select TIM1->CCMR1 &= ~(TIM_CCMR1_IC1F | TIM_CCMR1_CC1S); TIM1->CCMR1 |= TIM_CCMR1_CC1S_0; // CC1 channel = TI1 // external mode 1 TIM1->SMCR &= ~(TIM_SMCR_ECE | TIM_SMCR_TS | TIM_SMCR_SMS); // ECE must be ZERO!!!! TIM1->SMCR |= ( TIM_TS_TI1FP1 | TIM_SLAVEMODE_EXTERNAL1); TIM1->CR2 &= (uint16_t)~(TIM_CR2_TI1S | TIM_CR2_MMS); TIM1->CR2 |= (uint16_t)TIM_CR2_MMS_1; // TRGO update TIM1->CR1 |= (uint16_t)TIM_CR1_CEN; // Enable the TIM Counter // PA9 -> Input Capture pin as Timer1 IC2 GPIOA->AFR[1] &= 0xffffff0f; GPIOA->AFR[1] |= GPIO_AF1_TIM1 << 4; // (9-8)bit x 4 GPIOA->MODER &= ~(GPIO_MODER_MODER9); // AF GPIOA->MODER |= GPIO_MODER_MODER9_1; // alternate function mode GPIOA->PUPDR &= ~(GPIO_PUPDR_PUPDR9); // PU GPIOA->PUPDR |= GPIO_PUPDR_PUPDR9_0; // Pull-up mode // Initialize Timer1 IC2 TIM1->CCER &= (uint16_t)~TIM_CCER_CC2E; // Disable the CC2 // input filter + input select TIM1->CCMR1 &= ~(TIM_CCMR1_IC2F | TIM_CCMR1_CC2S); TIM1->CCMR1 |= TIM_CCMR1_CC2S_0; // positive edge TIM1->CCER &= (uint16_t)~(TIM_CCER_CC2P | TIM_CCER_CC2NP); TIM1->CCER |= (uint16_t)TIM_CCER_CC2E; // enable capture // Initialize Timer3(16bit) as slave counter of TIM1 // TIM1 overflow event -> ITR0 as Timer3 clock RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; TIM3->CR1 &= (uint16_t)(~(TIM_CR1_DIR | TIM_CR1_CMS | TIM_CR1_CKD)); // only counter overflow for interrupt TIM3->CR1 |= (uint16_t)TIM_CR1_URS; // Up counter uses from 0 to max(32bit) TIM3->ARR = 0xffff; // Use 16bit full TIM3->CCER = 0; // Reset all // external mode 1 TIM3->SMCR &= ~(TIM_SMCR_ECE | TIM_SMCR_TS | TIM_SMCR_SMS); TIM3->SMCR |= (TIM_TS_ITR0); // Set Internal Triger 0 (ITR0) TIM3->SMCR |= (TIM_SLAVEMODE_EXTERNAL1); // ECE must be ZERO!!!! TIM3->CR2 &= (uint16_t)~(TIM_CR2_TI1S | TIM_CR2_MMS); TIM3->CR2 |= (uint16_t)TIM_CR2_MMS_1; // TRGO update TIM3->CR1 |= (uint16_t)TIM_CR1_CEN; // Enable the TIM Counter // PB0 -> Input Capture pin as Timer3 IC3 GPIOB->AFR[0] &= 0xfffffff0; GPIOB->AFR[0] |= GPIO_AF2_TIM3 << 0; // 0bit x 4 GPIOB->MODER &= ~(GPIO_MODER_MODER0); // AF GPIOB->MODER |= GPIO_MODER_MODER0_1; // alternate function mode GPIOB->PUPDR &= ~(GPIO_PUPDR_PUPDR0); // PU GPIOB->PUPDR |= GPIO_PUPDR_PUPDR0_0; // Pull-up mode // Initialize Timer3 IC3 TIM3->CCER &= (uint16_t)~TIM_CCER_CC2E; TIM3->CCMR2 &= ~(TIM_CCMR2_CC3S | TIM_CCMR2_IC3F); TIM3->CCMR2 |= TIM_CCMR2_CC3S_0; // positive edge TIM3->CCER &= (uint16_t)~(TIM_CCER_CC3P | TIM_CCER_CC3NP); TIM3->CCER |= (uint16_t)TIM_CCER_CC3E; // enable capture // Up counter based on gate time period time_count = 0; // Only for Debug purpose PRINTF("\r\n// Timer1(16bit high(max48MHz) clock)\r\n"); PRINTF("// and Timer3(16bit low clock) combined up counter\r\n"); PRINTF("// Set GPIO for Timer1&3\r\n"); // PA PRINTF("// PA8 -> unkown frequency input pin as Timer1 CH1/TI1\r\n"); PRINTF("// PA9 -> Input Capture pin as Timer1 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); PRINTF("GPIOA->OTYPER 0x%08x:0x%08x\r\n",&GPIOA->OTYPER, GPIOA->OTYPER); PRINTF("GPIOA->OSPEEDR 0x%08x:0x%08x\r\n",&GPIOA->OSPEEDR, GPIOA->OSPEEDR); // PB PRINTF("// PB0 -> Input Capture pin as Timer3 CH3/TI3\r\n"); PRINTF("GPIOB->AFRL 0x%08x:0x%08x\r\n",&GPIOB->AFR[0], GPIOB->AFR[0]); PRINTF("GPIOB->AFRH 0x%08x:0x%08x\r\n",&GPIOB->AFR[1], GPIOB->AFR[1]); PRINTF("GPIOB->MODER 0x%08x:0x%08x\r\n",&GPIOB->MODER, GPIOB->MODER); PRINTF("GPIOB->PUPDR 0x%08x:0x%08x\r\n",&GPIOB->PUPDR, GPIOB->PUPDR); PRINTF("GPIOB->OTYPER 0x%08x:0x%08x\r\n",&GPIOB->OTYPER, GPIOB->OTYPER); PRINTF("GPIOB->OSPEEDR 0x%08x:0x%08x\r\n",&GPIOB->OSPEEDR, GPIOB->OSPEEDR); // TIM1 PRINTF("// PA8 -> Timer1(16bit) for an external up counter mode\r\n"); PRINTF("// PA9 -> Timer1 IC2\r\n"); PRINTF("TIM1->CR1 0x%08x:0x%08x\r\n",&TIM1->CR1, TIM1->CR1); PRINTF("TIM1->CR2 0x%08x:0x%08x\r\n",&TIM1->CR2, TIM1->CR2); PRINTF("TIM1->ARR 0x%08x:0x%08x\r\n",&TIM1->ARR, TIM1->ARR); PRINTF("TIM1->PSC 0x%08x:0x%08x\r\n",&TIM1->PSC, TIM1->PSC); PRINTF("TIM1->CCMR1 0x%08x:0x%08x\r\n",&TIM1->CCMR1, TIM1->CCMR1); PRINTF("TIM1->CCMR2 0x%08x:0x%08x\r\n",&TIM1->CCMR2, TIM1->CCMR2); PRINTF("TIM1->CCER 0x%08x:0x%08x\r\n",&TIM1->CCER, TIM1->CCER); PRINTF("TIM1->SMCR 0x%08x:0x%08x\r\n",&TIM1->SMCR, TIM1->SMCR); PRINTF("TIM1->DIER 0x%08x:0x%08x\r\n",&TIM1->DIER, TIM1->DIER); // TIM3 PRINTF("// PB0 -> Timer3 IC3\r\n"); PRINTF("TIM3->CR1 0x%08x:0x%08x\r\n",&TIM3->CR1, TIM3->CR1); PRINTF("TIM3->CR2 0x%08x:0x%08x\r\n",&TIM3->CR2, TIM3->CR2); PRINTF("TIM3->ARR 0x%08x:0x%08x\r\n",&TIM3->ARR, TIM3->ARR); PRINTF("TIM3->PSC 0x%08x:0x%08x\r\n",&TIM3->PSC, TIM3->PSC); PRINTF("TIM3->CCMR1 0x%08x:0x%08x\r\n",&TIM3->CCMR1, TIM3->CCMR1); PRINTF("TIM3->CCMR2 0x%08x:0x%08x\r\n",&TIM3->CCMR2, TIM3->CCMR2); PRINTF("TIM3->CCER 0x%08x:0x%08x\r\n",&TIM3->CCER, TIM3->CCER); PRINTF("TIM3->SMCR 0x%08x:0x%08x\r\n",&TIM3->SMCR, TIM3->SMCR); // Interrupt Timer3 IC3 (NOT Timer1 IC2) & Overflow timxpy_ready_flg = 0; timxpy_cnt_data = 0; sw_ovrflw_timxpy = 0; TIM1->SR = 0; // clear all IC/OC flag TIM3->SR = 0; // clear all IC/OC flag TIM3->DIER = 0; // Reset all interrupt flag TIM3->DIER = TIM_DIER_CC3IE + TIM_DIER_UIE; NVIC_SetVector(TIM3_IRQn, (uint32_t)irq_ic_TIMxPy); NVIC_ClearPendingIRQ(TIM3_IRQn); NVIC_EnableIRQ(TIM3_IRQn); PRINTF("TIM3->DIER 0x%08x:0x%08x\r\n\r\n",&TIM3->DIER, TIM3->DIER); PRINTF("RCC->APB1ENR 0x%08x:0x%08x\r\n\r\n",&RCC->APB1ENR, RCC->APB1ENR); } // Initialize TIM2 // IC2->PA1 for GPS 1pps signal // IC1->PA0 for Reciprocal frequency counting mode (Interrupt) void FRQ_CUNTR::initialize_TIMz(void) { // Initialize Timer2(32bit) for an internal(100MHz) 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 // input filter + input select TIM2->CCMR1 &= ~(TIM_CCMR1_IC1F | TIM_CCMR1_CC1S); TIM2->CCMR1 |= TIM_CCMR1_CC1S_0; TIM2->SMCR = 0; // Internal clock TIM2->CR1 |= (uint16_t)TIM_CR1_CEN; // Enable the TIM Counter // 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_1); // filter = fCLK/4 // positive edge TIM2->CCER &= (uint16_t)~(TIM_CCER_CC1P | TIM_CCER_CC1NP); TIM2->CCER |= (uint16_t)TIM_CCER_CC1E; // enable capture // 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 TIM2->CCER &= (uint16_t)~TIM_CCER_CC2E; // Disable the CC TIM2->CCMR1 &= ~(TIM_CCMR1_IC2F | TIM_CCMR1_CC2S); //TIM2->CCMR1 |= TIM_CCMR1_CC2S_0; // filter none TIM2->CCMR1 |= (TIM_CCMR1_CC2S_0 + TIM_CCMR1_IC2F_1); // filter = fCLK/4 // positive edge TIM2->CCER &= (uint16_t)~(TIM_CCER_CC2P | TIM_CCER_CC2NP); TIM2->CCER |= (uint16_t)TIM_CCER_CC2E; // enable capture // Up counter based on gate time period time_count_onepps = 0; // 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); // Interrupt Timer2 IC4(disable at this moment) & Overflow timz_cnt_data = 0; sw_ovrflw_timz = 0; TIM2->SR = 0; // clear all IC/OC flag TIM2->DIER = 0; // Disable all interrupt TIM2->DIER = TIM_DIER_UIE; // set only overflow NVIC_SetVector(TIM2_IRQn, (uint32_t)irq_ic_TIMz); 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; // clear IC flag TIM2->DIER |= TIM_DIER_CC1IE; // Enable IC1 __enable_irq(); } //------------------------------------------------------------------------------ // Frequency check for test & debug purpose //------------------------------------------------------------------------------ // Read TIM1(+TIM3) Input frequency uint32_t FRQ_CUNTR::debug_read_input_frequency(double gatetime) { TIM1->CR1 &= ~(uint16_t)TIM_CR1_CEN; // disable the TIM1 Counter TIM3->CNT = 0; TIM1->CNT = 0; TIM1->CR1 |= (uint16_t)TIM_CR1_CEN; // Enable the TIM1 Counter wait(gatetime); // Gate time for count TIM1->CR1 &= ~(uint16_t)TIM_CR1_CEN; // disable the TIM1 Counter uint32_t freq = (TIM3->CNT << 16) + TIM1->CNT; TIM1->CR1 |= (uint16_t)TIM_CR1_CEN; // Enable the TIM1 Counter PRINTF("Input freq.=%10d [Hz], gate= %4.2f [Sec]\r\n", freq, gatetime); return freq; // read counter } // Read TIM2 Clock frequency uint32_t FRQ_CUNTR::debug_read_base_clock_frequency(double gatetime) { TIM2->CNT = 0; wait(gatetime); // Gate time for count uint32_t freq = TIM2->CNT; // read counter PRINTF("Clock Counter=%10d, gate= %4.2f [Sec]\r\n", freq, gatetime); return freq; // return counter data } // Dump all buffered data void FRQ_CUNTR::debug_printf_all_buffer(void) { fdt_buffer.debug_print_all_buffer(); } //------------------------------------------------------------------------------ // Interrupt Handlers //------------------------------------------------------------------------------ // GPS 1PPS signal interrupt (connected to TIM3 IC3, TIM1 IC2 and TIM2 IC2) // TIM3 IC3 Interrupt control void irq_ic_TIMxPy(void) { // IC3 (GPS 1PPS) if (TIM3->SR & TIM_SR_CC3IF){ TIM1->SR &= ~TIM_SR_CC2IF; // clear IC flag TIM3->SR &= ~TIM_SR_CC3IF; // clear IC flag TIM2->SR &= ~TIM_SR_CC2IF; // clear IC flag timxpy_cnt_data = (TIM3->CCR3 << 16) + TIM1->CCR2; // 16+16 bit timxpy_ready_flg = 1; timz_cnt_data = TIM2->CCR2; // 32 bit // data saves into the ring buffer / Unknown Freq. fdt.freq_dt = timxpy_cnt_data; fdt.f_sw_dt = sw_ovrflw_timxpy; fdt.t_cnt = ++time_count; fdt_buffer.ring_put_dt(fdt.f_1sec_dt); // data saves into the ring buffer / F411 internal clock onepps_dt.freq_dt = timz_cnt_data; onepps_dt.f_sw_dt = sw_ovrflw_timz; onepps_dt.t_cnt = ++time_count_onepps; onepps_buf.ring_put_dt(onepps_dt.f_1sec_dt); #if ACTIVE_LED_TIMX irq_led1 = !irq_led1; #endif // ACTIVE_LED } // TIM3 overflow if (TIM3->SR & TIM_SR_UIF){ TIM3->SR &= ~TIM_SR_UIF; ++sw_ovrflw_timxpy; } } // Reciprocal data (TIM2 IC1) void irq_ic_TIMz(void) { // IC1 (for reciprocal measurement) if (TIM2->SR & TIM_SR_CC1IF){ TIM2->SR &= ~TIM_SR_CC1IF; // clear IC flag uint32_t data = TIM2->CCR1; if (recipro_step == 0){ // start measuring recipro_start = data; recipro_step = 1; } else if (recipro_step == 1){ // stop TIM2->DIER &= ~TIM_DIER_CC1IE; // disable IC4 interrupt recipro_stop = data; recipro_step = 2; } else { // jsut in case TIM2->DIER &= ~TIM_DIER_CC1IE; // disable IC4 interrupt recipro_step = 0; } #if ACTIVE_LED_TIMZ irq_led1 = !irq_led1; #endif // ACTIVE_LED } // TIM2 overflow if (TIM2->SR & TIM_SR_UIF){ // 32bit counter overflow TIM2->SR &= ~TIM_SR_UIF; ++sw_ovrflw_timz; } } #endif // #if defined(TARGET_NUCLEO_F411RE) || defined(TARGET_NUCLEO_F446RE)