PSoC 4200 Prototyping Kit (11)
レシプロカル周波数カウンタ (周期カウンタ) のプログラム (の断片) を示します。
pcnt 変数、pcnt_Start() 関数、pcnt_Stop() 関数、calc_crt() 関数の定義はヘッダ・ファイル (pcnt.h)、C ソース・ファイル (pcnt.c) として独立させ、main.c と同じフォルダに置いて pcnt.c をプロジェクトに追加します。
「pcnt.h」
#ifndef _PCNT_H_ #define _PCNT_H_ /*************************************************/ /* pcnt.h : 32 bit Period counter */ /* by 2 x 16 bit TCPWM component */ /* using Chinese Remainder Theorem */ /* */ /* 2015/02/03 by pcm1723 */ /*************************************************/ // #include <project.h> // // period counter defines // #define cap_m1_shift (16UL) #define cap_m1 (1UL << cap_m1_shift) #define cap_m2 (cap_m1 - 1UL) #define TIMER1_CLK_MHz 48UL #define TIMER1_CLK_Hz (TIMER1_CLK_MHz * 1000000UL) // // uncomment following line // to use assembler version of CRT //#define USE_ASM_CRT // typedef struct tag_pcnt_t { int32_t ncyc; // # of cycles (#_of_edges - 1) uint32_t cap; // 32 bit counter capture uint32_t cap0; // 32 bit counter capture of the first edge int32_t tc_cnt; // TC count int32_t tc_max; // TC MAX count for the gatetime uint32_t dur; // calculated duration int32_t ready; // measurement finish flag } pcnt_t; // // period counter variables // extern volatile pcnt_t pcnt; // // period counter functions // void pcnt_Stop( void ); void pcnt_Start( int16_t ms ); uint32_t crt_calc(uint16_t c1, uint16_t c2); // #endif // #ifndef _PCNT_H_
「pcnt.c」
/*************************************************/ /* pcnt.c : 32 bit Period counter */ /* by 2 x 16 bit TCPWM component */ /* using Chinese Remainder Theorem */ /* */ /* 2015/02/03 by pcm1723 */ /*************************************************/ // #include "pcnt.h" // // period counter variable // volatile pcnt_t pcnt; // // stop measurement function // void pcnt_Stop( void ) { // stop both counter Timer1_TriggerCommand((Timer1_MASK | Timer2_MASK), (Timer1_CMD_STOP)); // disable Timer1 interrupts Timer1_SetInterruptMode(0); // clear pending interrupts Timer1_ClearInterrupt(Timer1_INTR_MASK_CC_MATCH); Timer1_ClearInterrupt(Timer1_INTR_MASK_TC); pcnt.ready = 0; // not ready } // void pcnt_Stop() // // start period counter measurement // for specified gatetime in terms of millisecond // by argument 'ms' // void pcnt_Start( int16_t ms ) { // stop both counter at first pcnt_Stop(); if (0 < ms) { // valid gatetime given // Max TC counts for specified gatetime by argument 'ms' pcnt.tc_max = (((TIMER1_CLK_MHz * 1000UL) * ms + 32768UL) >> 16); if (0 == pcnt.tc_max) { pcnt.tc_max = 1; } // at least '1' pcnt.tc_cnt = 0; // clear TC counter pcnt.ncyc = -1; // mark no edge found pcnt.cap = 0; // clear captured value pcnt.cap0 = 0; // clear captured value of the first edge // start (reload) both counter simultaneously Timer1_TriggerCommand((Timer1_MASK | Timer2_MASK), (Timer1_CMD_RELOAD)); // enable Timer1 TC, CC interrupt Timer1_SetInterruptMode(Timer1_INTR_MASK_TC | Timer1_INTR_MASK_CC_MATCH); } // if (0 < ms) { ... } // void pcnt_Start() // // crt_calc() : Chinese Remainder Theorem calculation // // argumnent: // // r0 : (uint16_t) c1 = (n mod M1) // r1 : (uint16_t) c2 = (n mod M2) // // (M1 = 2**16 = 65536) // (M2 = (M1 - 1) = (2**16 - 1) = 65535) // // result: // r0 : (uint32_t) n // #if defined(USE_ASM_CRT) // inline assembler version // // suppress warning about 'return' #pragma GCC diagnostic ignored "-Wreturn-type" // // inline assembler verision // uint32_t crt_calc(uint16_t c1, uint16_t c2) { __asm__ volatile ( " cmp r1,r0 \n\t" " sbc r1,r0 \n\t" " lsl r1,#16 \n\t" " add r0,r1 \n\t" ); // asm } // uint32_t crt_calc() // restore waring message #pragma GCC diagnostic warning "-Wreturn-type" #else // C version uint32_t crt_calc(uint16_t a1, uint16_t a2) { register uint32_t n; n = a2; n -= a1; n += (n >> 16); n = (n << 16) + a1; return(n); } // uint32_t crt_calc() #endif
Timer1 コンポーネントに接続するインタラプト・コンポーネントのインスタンス名を「Timer1_ISR」と命名した場合には、対応する C ソース・ファイルは
Generated_Source/PSoc4
フォルダの下に「Timer1_ISR.c」という名前で生成されますから、下のリストのように CY_ISR(Timer1_ISR_Interrupt) 関数に記述を追加します。
/* Place your Interrupt code here. */
と書いてある部分に記述しておかないと、トップレベル・デザインの変更後のビルドでファイルが再生成される場合に、せっかく書いた記述が消されてしまいます。
「Timer1_ISR.c」
/******************************************************************************* * File Name: Timer1_ISR.c * Version 1.70 * * Description: * API for controlling the state of an interrupt. * * * Note: * ******************************************************************************** * Copyright 2008-2012, Cypress Semiconductor Corporation. All rights reserved. * You may use this file only in accordance with the license, terms, conditions, * disclaimers, and limitations in the end user license agreement accompanying * the software package with which this file was provided. *******************************************************************************/ #include <cydevice_trm.h> #include <CyLib.h> #include <Timer1_ISR.h> #if !defined(Timer1_ISR__REMOVED) /* Check for removal by optimization */ /******************************************************************************* * Place your includes, defines and code here ********************************************************************************/ /* `#START Timer1_ISR_intc` */ #include "../../pcnt.h" /* `#END` */ . . . . . <中略> . . . . . /******************************************************************************* * Function Name: Timer1_ISR_Interrupt ******************************************************************************** * * Summary: * The default Interrupt Service Routine for Timer1_ISR. * * Add custom code between the coments to keep the next version of this file * from over writting your code. * * Parameters: * None * * Return: * None * *******************************************************************************/ CY_ISR(Timer1_ISR_Interrupt) { /* Place your Interrupt code here. */ /* `#START Timer1_ISR_Interrupt` */ // // TC (Terminal Count) interrupt check // if (Timer1_INTR_MASK_TC & Timer1_GetInterruptSourceMasked()) { // Terminal Count interrupt occurred, clear source Timer1_ClearInterrupt(Timer1_INTR_MASK_TC); if (pcnt.tc_max <= (++pcnt.tc_cnt)) { // end of gate time pcnt_Stop(); // stop timers // calculate duration pcnt.dur = (pcnt.cap - pcnt.cap0); pcnt.ready = 1; // set data ready flag } // if (pcnt.tc_max == ... } // if (Timer1_INTR_MASK_TC & ... // // CC (Capute/Compare) interrupt check // if (Timer1_INTR_MASK_CC_MATCH & Timer1_GetInterruptSourceMasked()) { // Capture interrupt occurred, clear sorce Timer1_ClearInterrupt(Timer1_INTR_MASK_CC_MATCH); if (0 == pcnt.ready) { // gate ON // Calculate 32-bit solution from two 16-bit remainders // by CRT (Chinese Remainder Theorem) pcnt.cap = crt_calc(Timer1_COMP_CAP_REG, Timer2_COMP_CAP_REG); if (0 == (++pcnt.ncyc)) { // the very first edge pcnt.cap0 = pcnt.cap; // remember the first edge } // if (0 == ... } // if (0 == pcnt.ready) { ... } // if (Timer1_INTR_MASK_CC_MATCH & ... /* `#END` */ } . . . . . <中略> . . . . . /* [] END OF FILE */
main.c 関数の測定に関係する部分だけを下に示します。 UART や I2C LCD に表示する部分は全く省略しています。
/* ======================================== * * Copyright YOUR COMPANY, THE YEAR * All Rights Reserved * UNPUBLISHED, LICENSED SOFTWARE. * * CONFIDENTIAL AND PROPRIETARY INFORMATION * WHICH IS THE PROPERTY OF your company. * * ======================================== */ #include <project.h> #include "pcnt.h" #define GATETIME_ms (1001) int main() { /* Place your initialization/startup code here (e.g. MyInst_Start()) */ Timer1_Start(); Timer1_ISR_Start(); Timer2_Start(); pcnt_Stop(); CyGlobalIntEnable; /* Uncomment this line to enable global interrupts. */ pcnt_Start(GATETIME_ms); // start measurement for(;;) { /* Place your application code here. */ if (pcnt.ready) { // measurement done if (0 >= pcnt.ncyc) { // valid cycles not found ///////////// display measurement failed ////////////// } else { // valid cyceles found ///////////// display measurement result ////////////// } // if (0 >= pcnt.ncyc) { ... // start next measurement pcnt_Start(GATETIME_ms); } // if (pcnt.ready) { ... } // for (;;) } // int main() /* [] END OF FILE */