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 */