Beaglebone BlackのDMTimerで周波数カウンタを作る

Beagle Bone Black
前回BBBのDMTimerを用いてTimer出力の試行を行った。
引き続き今度はDMtimerのtimer captureを試す。
多少実用的にするために任意の入力信号の周波数測定を行うサンプルデモとした。

AM335Xのレジスタ詳細に関しては以下のドキュメント参照。
AM335x Sitara(TM) Processors Technical Reference Manual

DMTimerのcapture機能はTIMx_OUTを入力に切り替え、基準クロックTimer TCRRを走らせておき、TIMx_OUTに入力された任意の信号のエッジ割り込みが発生した際のTCRRの値をキャプチャする。
言い換えるとTIMx_OUTに入力された任意の信号のエッジ割り込み二回分のキャプチャ結果の差により入力信号の周波数を求めることができる。

ただ、DMTimerのcapture modeは今一つ使いどころが難しい。
正直に言って使い難い。
同じtimer capture機能でもeCAP moduleのcapture modeの方がはるかに実用的である。
使い難い理由は主に以下。
・Prescalerが入力信号側ではなく基準クロック側にしかきかない。
・TCAR_IT_FLAGをクリアしなければcaptureを3回以上連続で行うことができない。

eCAP moduleでは入力信号側にPrescalerがあるので、入力信号を分周することにより精度を上げることができるので意味がある。
DMTimerでは計測する側の基準クロックの分周しかできないので、通常の使い方では高精度の周波数測定ができないと思われる。
TCAR_IT_FLAGをクリアしなければならないということは、レジスタ設定だけを行い必要なタイミングでそのタイミングでのキャプチャ結果を読みに行くような使い方ができないので何かしらのソフトウェア制御が必要となるだろう。
二回までの連続キャプチャは可能なので、devmem2でレジスタ設定を行って結果をポーリングするような使い方は可能である。
尚、私がDMTimerのcapture modeの設計意図を理解していないだけでもっと便利な使い方があるかもしれない。

とは言え、この手のペリフェラルロジックは工夫次第で応用範囲が広がるものである。
今回二つのDMTimerをPRUから制御を行い、比較的高精度の周波数測定を実現させる。
実装する構成の信号の流れは以下の図のようになる。

基本的なアイデアは以下。
・TIMER4を基準クロックCLK_M_OSCとし10HzのTimer出力とする。
・TIMER5を基準クロックtclkin、capture modeとしTIM5_OUTからの10HzのTimer出力を入力とする。

この構成で、10Hzの入力クロックの立ち上がりエッジ間に基準クロックtclkinが何回カウントされるかをcaptureする。
つまり主客を逆にしてTIM5_OUTの入力信号を基準に、tclkinの周波数を計測するわけだ。
TCAR_IT_FLAGのクリアと計測結果及びタイミングのホストへの通知はPRUにより行う。
ついでにTIMER6からtclkinの四分周の波形を、TIMER7からtclkinの四分周の反転波形の出力を行う。
TIMER4からの出力、すなわちTIMER5への入力周波数は単位計測周期を作るが既知であればなんでも良く、周波数が高ければ計測時間が短くなる代わりに計測精度が悪くなり、反対に周波数が低ければ計測精度が高くなる代わりに測定時間が長くなる。
10Hzであれば100msec毎の計測となるので周波数の変動への追随は比較的早く使いやすいのではないだろうか。

尚、今回は実装していないが、別解として以下もあるだろう。
・TIMER5を基準クロックtclkin、分周比nのタイマ出力としてTIM5_OUTから出力させる。
・TIMER4を基準クロックCLK_M_OSC、capture modeとしTIM5_OUTからのTimer出力を入力とする。

この構成ではtclkinに測定信号を入れ、TIMER5をPrescalerとして用いて周波数を下げ、TIMER4でキャプチャする。
多分この構成の方がDMTIMERのcapture modeとして素直であろう。
測定時間がtclkinへの入力信号周波数依存となることを嫌い採用しなかった。

今回も前回までの環境が構築されている前提とする。

Beagle Bone BlackのPRUを学ぶ(その4)
Beagle Bone BlackのPRUを学ぶ(その3)
Beagle Bone BlackのPRUを学ぶ(その2)
Beagle Bone BlackのPRUを学ぶ(その1)

先ずはdevice treeの設定。
今回は以下のように使う。

TIMER4_OUT: P8_7
TIMER5_IN: P8_9
TIMER6_OUT: P8_10
TIMER7_OUT: P8_8
tclkin: P9_41
24.576M_CLK_OUT: P9.25

前回も述べたが、TIMER4~TIMER7は少なくともKernel3.8ベースではドライバとしてサポートされていない。
よって、device treeのoverrayではpinmuxの設定だけを行い、DMTimerの設定はPRUプログラムで行うこととする。

tclkinはP9_41にアサインされているが、P9_41はAM335XのBot D14だけでなくBBB内部でBot D13:gpio3[20]にも接続されている。
従ってP9_41をtclkinとして使用する場合はgpio3[20]をhigh-Zに設定する必要がある。

また、既知の周波数である入力信号が欲しいのでBBBに搭載されているP9.25の24.576MHzオシレータのCLK出力を用いる。
24.576MHzのオシレータのOEはBBB内部でBot V17:gpio1[27]に結線されているので入力かつプルアップ設定とする。

BeagleBone Black Rev.Cのピンアサイン表参照。

以上を踏まえ、各GPIO pinmuxを設定するためのdtsファイルを書いてみた。

/dts-v1/;
/plugin/;
 
/ {
    compatible = "ti,beaglebone", "ti,beaglebone-black";
 
    /* identification */
    part-number = "bone-JB-DMTIMER";
    version = "00A0";
 
    exclusive-use =
        /* pin header uses */
        "P8.7",  /* timer4_P8_7:   [Bot R7 ] timer4_mux3 */
        "P8.8",  /* timer7_P8_8:   [Bot T7 ] timer7_mux3 */
        "P8.10", /* timer6_P8_10:  [Bot U6 ] timer6_mux3 */
        "P8.9",  /* timer5_P8_9:   [Bot T6 ] timer5_mux3 */
        "P9.41", /* timer_P9_41:   [Bot D14] tclkin     ! shared use ! */
                 /* gpio3_P9_41:   [Bot D13] gpio3[20]  ! shared use ! */
                    /* P9.41 is shared resource that is connected with both D14 and D13.
                       Since we wll use function on D14 as input pin, D13 has to be set
                       to input(high-Z). */
        "P9.25", /* gpio3_P9_25:   [Bot A14] gpio3[21] */
                    /* P9.25 is conected with 24.576MHz oscillator CLK.
                       This oscillator is enabled and disabled with gpio1[27] */
 
        /* the hardware IP uses */
        "timer4",
        "timer5",
        "timer6",
        "timer7";
 
    fragment@0 {
        target = <&am33xx_pinmux>;
        __overlay__ {
            timer_gpio: pinmux_timer_pins {
                pinctrl-single,pins = <
                    /* TIMx_OUT settings */
                    0x090 0x0a  /* [Bot R7 ] (IDIS|OFF|MODE2)=(0 01 010) timer4_mux3 P8_7 */
                    0x094 0x0a  /* [Bot T7 ] (IDIS|OFF|MODE2)=(0 01 010) timer7_mux3 P8_8 */
                    0x098 0x0a  /* [Bot U6 ] (IDIS|OFF|MODE2)=(0 01 010) timer6_mux3 P8_10 */
                    0x09C 0x22  /* [Bot T6 ] (IEN |PD |MODE2)=(1 00 010) timer5_mux3 P8_9 */
 
                    /* tclkin settings */
                    0x1A8 0x2f  /* [Bot D13] (IEN |OFF|MODE7)=(1 01 111) gpio3[20] P9_41# */
                    0x1B4 0x22  /* [Bot D14] (IEN |PD |MODE2)=(1 00 010) tclkin P9_41# */
 
                    /* 24.576MHz oscillator settings */
                    0x06C 0x37  /* [Bot V17] (IEN |PU |MODE7)=(1 10 111) gpio1[27] OSC_OE */
                    0x1AC 0x2f  /* [Bot A14] (IEN |OFF|MODE7)=(1 01 111) gpio3[21] p9_25 */
                >;
            };
        };
    };
 
    fragment@1 {
        target = <&ocp>;
        __overlay__ {
            test_helper: helper {
                compatible = "bone-pinmux-helper";
                pinctrl-names = "default";
                pinctrl-0 = <&timer_gpio>;
                status = "okay";
            };
        };
    };
 
    fragment@2 {
        target = <&pruss>;
        __overlay__ {
            status = "okay";
        };
    };
};

このdtsファイルをbone-JB-DMTIMER-00A0.dtsという名前で/lib/firmwareに保存して以下のようにdtcでコンパイルする。

debian@beaglebone:~$ sudo -s
root@beaglebone:/home/debian# cd /lib/firmware/
root@beaglebone:/lib/firmware# dtc -@ -O dtb -o bone-JB-DMTIMER-00A0.dtbo bone-JB-DMTIMER-00A0.dts
root@beaglebone:/lib/firmware# reboot

念の為にリブートを行う。

ちなみに使用するピンのデフォルトでのpinmuxは全てmode7の入力となっている。

debian@beaglebone:~$ sudo -s
root@beaglebone:/home/debian# export PINS=/sys/kernel/debug/pinctrl/44e10800.pinmux/pins
root@beaglebone:/home/debian# cat $PINS | grep 890
pin 36 (44e10890) 00000037 pinctrl-single
root@beaglebone:/home/debian# cat $PINS | grep 894
pin 37 (44e10894) 00000037 pinctrl-single
root@beaglebone:/home/debian# cat $PINS | grep 898
pin 38 (44e10898) 00000037 pinctrl-single
root@beaglebone:/home/debian# cat $PINS | grep 89c
pin 39 (44e1089c) 00000037 pinctrl-single
root@beaglebone:/home/debian# cat $PINS | grep 9a8
pin 106 (44e109a8) 00000027 pinctrl-single
root@beaglebone:/home/debian# cat $PINS | grep 9b4
pin 109 (44e109b4) 00000027 pinctrl-single
root@beaglebone:/home/debian# cat $PINS | grep 86c
pin 27 (44e1086c) 00000027 pinctrl-single
root@beaglebone:/home/debian# cat $PINS | grep 9ac
pin 107 (44e109ac) 00000027 pinctrl-single
root@beaglebone:/home/debian#

再立ち上げ後root権限でcapemgrにbone-JB-DMTIMERを与える。

debian@beaglebone:~$ sudo -s
root@beaglebone:/home/debian# export SLOTS=/sys/devices/bone_capemgr.*/slots
root@beaglebone:/home/debian# echo bone-JB-DMTIMER > $SLOTS
root@beaglebone:/home/debian# cat $SLOTS
 0: 54:PF---
 1: 55:PF---
 2: 56:PF---
 3: 57:PF---
 4: ff:P-O-L Bone-LT-eMMC-2G,00A0,Texas Instrument,BB-BONE-EMMC-2G
 5: ff:P-O-- Bone-Black-HDMI,00A0,Texas Instrument,BB-BONELT-HDMI
 6: ff:P-O-- Bone-Black-HDMIN,00A0,Texas Instrument,BB-BONELT-HDMIN
 7: ff:P-O-L Override Board Name,00A0,Override Manuf,bone-JB-DMTIMER
root@beaglebone:/home/debian#

pinmuxが設定されているか確認。

root@beaglebone:/home/debian# export PINS=/sys/kernel/debug/pinctrl/44e10800.pinmux/pins
root@beaglebone:/home/debian# cat $PINS | grep 890
pin 36 (44e10890) 0000000a pinctrl-single
root@beaglebone:/home/debian# cat $PINS | grep 894
pin 37 (44e10894) 0000000a pinctrl-single
root@beaglebone:/home/debian# cat $PINS | grep 898
pin 38 (44e10898) 0000000a pinctrl-single
root@beaglebone:/home/debian# cat $PINS | grep 89c
pin 39 (44e1089c) 00000022 pinctrl-single
root@beaglebone:/home/debian# cat $PINS | grep 9a8
pin 106 (44e109a8) 0000002f pinctrl-single
root@beaglebone:/home/debian# cat $PINS | grep 9b4
pin 109 (44e109b4) 00000022 pinctrl-single
root@beaglebone:/home/debian# cat $PINS | grep 86c
pin 27 (44e1086c) 00000037 pinctrl-single
root@beaglebone:/home/debian# cat $PINS | grep 9ac
pin 107 (44e109ac) 0000002f pinctrl-single
root@beaglebone:/home/debian#

意図通りに設定できていることが確認できた。

PRUのソースコードを以下に晒す。

// dmtimer.p

.origin 0
.entrypoint DMTIMER_SAMPLE

#include &quot;dmtimer.hp&quot;

// Our plan to use Registers
//     R0-R4: temporary use
//     R10: Address of CM_PER_BASE
//     R11: Address of CM_DPLL_BASE
//     R12: Address of DMTIMER4_BASE
//     R13: Address of DMTIMER5_BASE
//     R14: Address of DMTIMER6_BASE
//     R15: Address of DMTIMER7_BASE
//     R17-R20: always all ZERO

// I/F with Host
//   CONST_PRUSHAREDRAM + 0x00: size 4Byte: Status value to indicate to host.
//   CONST_PRUSHAREDRAM + 0x04: size 4Byte: Frequency value to indicate to host.

// Our plan to use timers
//     TIMER4: Make 1Hz wave
//     TIMER5: Capture Frequency value of TCLKIN with feedback TIMER4
//     TIMER6: Make positive phase wave which divided TCLKIN by 2
//     TIMER7: Make negative phase wave which divided TCLKIN by 2

DMTIMER_SAMPLE:
// Make Constant values for registers
    MOV       r10, CM_PER_BASE          // r10 is Address of CM_PER_BASE
    MOV       r11, CM_DPLL_BASE         // r11 is Address of CM_DPLL_BASE
    MOV       r12, DMTIMER4_BASE        // r12 is Address of DMTIMER4_BASE
    MOV       r13, DMTIMER5_BASE        // r13 is Address of DMTIMER5_BASE
    MOV       r14, DMTIMER6_BASE        // r14 is Address of DMTIMER6_BASE
    MOV       r15, DMTIMER7_BASE        // r15 is Address of DMTIMER7_BASE

    MOV       r17, 0x00000000           // r17 is always all ZERO
    MOV       r18, r17                  // also r18-r20 are always all ZERO
    MOV       r19, r17                  //
    MOV       r20, r17                  // 

// Enable OCP Master port
    LBCO      r0, CONST_PRUCFG, OFFSET_CFG_SYSCFG_REG, 4  // r0 = *(CONST_PRUCFG + OFFSET_CFG_SYSCFG_REG)
    CLR       r0, r0, 4                                   // Clear bit4 of r0 (Clear SYSCFG:STANDBY_INIT
                                                          // to enable OCP master port)
    SBCO      r0, CONST_PRUCFG, OFFSET_CFG_SYSCFG_REG, 4  // *(CONST_PRUCFG + OFFSET_CFG_SYSCFG_REG) = r0

// Init Indexs and Pointers of Constant tables
    MOV       r0, PRU0_CTRL_REG_BASE             //
    SBBO      r17, r0, OFFSET_PRU_CTBIR0_REG, 4  // *(PRU0_CTRL_REG_BASE + OFFSET_PRU_CTBIR0_REG) = r17:0x00000000
                                                 //   Set Fields C25_BLK_INDEX and C24_BLK_INDEX to 0.
    MOV       r1, 0x00000100                     //
    SBBO      r1, r0, OFFSET_PRU_CTPPR0_REG, 4   // *(PRU0_CTRL_REG_BASE + OFFSET_PRU_CTPPR0_REG) = r1:0x00000100
                                                 //   Set Fields C29_POINTER to 0x0000 and C28_POINTER to 0x0100.
                                                 //   Unexpectedly, C28 is NOT dedicated for Shared PRU RAM,
                                                 //   we can use C28 for PRU0/1 Local Data RAM if C28_POINTER
                                                 //   in CTPPRx register is set to 0x0000/0x0020. So to use
                                                 //   for Shared PRU RAM C28_POINTER must be set to 0x0100.

INIT_DMTIMER:
// Init Indication params for/from Host
    SBCO      r17, CONST_PRUSHAREDRAM, 0x00, 4   // *(CONST_PRUSHAREDRAM + 0) = r17:0x00000000
    SBCO      r17, CONST_PRUSHAREDRAM, 0x04, 4   // *(CONST_PRUSHAREDRAM + 4) = r17:0x00000000

// Enable DMTIMER modules
    MOV       r0, 0x00000002                            //
    SBBO      r0, r10, OFFSET_CM_PER_TIMER4_CLKCTRL, 4  // *(r10:CM_PER_BASE + OFFSET_CM_PER_TIMER4_CLKCTRL) = r0:00000002
                                                        //   0x44E00088 : 0x00000002
    SBBO      r0, r10, OFFSET_CM_PER_TIMER5_CLKCTRL, 4  // *(r10:CM_PER_BASE + OFFSET_CM_PER_TIMER5_CLKCTRL) = r0:00000002
                                                        //   0x44E000ec : 0x00000002
    SBBO      r0, r10, OFFSET_CM_PER_TIMER6_CLKCTRL, 4  // *(r10:CM_PER_BASE + OFFSET_CM_PER_TIMER6_CLKCTRL) = r0:00000002
                                                        //   0x44E000f0 : 0x00000002
    SBBO      r0, r10, OFFSET_CM_PER_TIMER7_CLKCTRL, 4  // *(r10:CM_PER_BASE + OFFSET_CM_PER_TIMER7_CLKCTRL) = r0:00000002
                                                        //   0x44E0007c : 0x00000002
                                                 // TIMERx_CLKCTRL are manage the TIMERx clocks.
                                                 //     31-18 Reserved
                                                 //     17-16 IDLEST : Module idle status.
                                                 //         0x0 = Func : Module is fully functional, including OCP
                                                 //         0x1 = Trans : Module is performing transition: wakeup,
                                                 //                       or sleep, or sleep abortion
                                                 //         0x2 = Idle : Module is in Idle mode (only OCP part).
                                                 //                      It is functional if using separate functional clock
                                                 //         0x3 = Disable : Module is disabled and cannot be accessed
                                                 //     15-2 Reserved
                                                 //     1-0 MODULEMODE : Control the way mandatory clocks are managed.
                                                 //         0x0 = DISABLED : Module is disable by SW. Any OCP access to module
                                                 //                          results in an error, except if resulting
                                                 //                          from a module wakeup (asynchronous wakeup).
                                                 //         0x1 = RESERVED_1 : Reserved
                                                 //       * 0x2 = ENABLE : Module is explicitly enabled. Interface clock
                                                 //                        (if not used for functions) may be gated according
                                                 //                        to the clock domain state. Functional clocks are
                                                 //                        guarantied to stay present. As long as in this
                                                 //                        configuration, power domain sleep

    // just in case we check TIDR registers
    LBBO      r0, r12, OFFSET_TIDR, 4            // r0 = *(r12:DMTIMER4_BASE + OFFSET_TIDR)
                                                 //   0x48044000 : 0x40000100
    LBBO      r0, r13, OFFSET_TIDR, 4            // r0 = *(r13:DMTIMER5_BASE + OFFSET_TIDR)
                                                 //   0x48046000 : 0x40000100
    LBBO      r0, r14, OFFSET_TIDR, 4            // r0 = *(r14:DMTIMER6_BASE + OFFSET_TIDR)
                                                 //   0x48048000 : 0x40000100
    LBBO      r0, r15, OFFSET_TIDR, 4            // r0 = *(r15:DMTIMER7_BASE + OFFSET_TIDR)
                                                 //   0x4804A000 : 0x40000100
                                                 // TIDR Register
                                                 //     TIDR register is fixed value as 0x40000100.

    // we stop and configure DMTIMERs
    MOV       r0, 0x00001402                     // TIMER4 is used to make 1Hz clock.
    SBBO      r0, r12, OFFSET_TCLR, 4            // *(r12:DMTIMER4_BASE + OFFSET_TCLR) = r0:0x00001402
                                                 //   0x48044038: 0x00001402
                                                 //       0000 0000 0000 0000 0001 0100 0000 0010
                                                 // TCLR Register
                                                 //     31-15 RESERVED
                                                 //     14 GPO_CFG : General purpose output this register
                                                 //        drives directly the PORGPOCFG output pin
                                                 //       * 0h = PORGPOCFG drives 0 and configures the timer pin
                                                 //              as an output.
                                                 //         1h = PORGPOCFG drives 1 and configures the timer pin
                                                 //              as an input.
                                                 //     13 CAPT_MODE : Capture mode.
                                                 //       * 0h = Single capture
                                                 //         1h = Capture on second event
                                                 //     12 PT : Pulse or toggle mode on PORTIMERPWM output pin
                                                 //         0h = Pulse
                                                 //       * 1h = Toggle
                                                 //     11-10 TRG : Trigger output mode on PORTIMERPWM output pin
                                                 //         0h = No trigger
                                                 //       * 1h = Trigger on overflow
                                                 //         2h = Trigger on overflow and match
                                                 //         3h = Reserved
                                                 //     9-8 TCM : Transition Capture Mode on PIEVENTCAPT input pin
                                                 //       * 0h = No capture
                                                 //         1h = Capture on low to high transition
                                                 //         2h = Capture on high to low transition
                                                 //         3h = Capture on both edge transition
                                                 //     7 SCPWM : This bit should be set or clear while
                                                 //                    the timer is stopped or the trigger is off
                                                 //       * 0h = Clear the PORTIMERPWM output pin and select positive
                                                 //              pulse for pulse mode
                                                 //         1h = Set the PORTIMERPWM output pin and select negative
                                                 //              pulse for pulse mode
                                                 //     6 CE :
                                                 //       * 0h = Compare mode is disabled
                                                 //         1h = Compare mode is enabled
                                                 //     5 PRE : Prescaler enable
                                                 //       * 0h = The TIMER clock input pin clocks the counter
                                                 //         1h = The divided input pin clocks the counter
                                                 //     4-2 PTV : Pre-scale clock Timer value
                                                 //       * 0h = x2
                                                 //     1 AR :
                                                 //         0h = One shot timer
                                                 //       * 1h = Auto-reload timer
                                                 //     0 ST : In the case of one-shot mode selected (AR = 0),
                                                 //                 this bit is automatically reset by internal logic
                                                 //                 when the counter is overflowed.
                                                 //       * 0h (R) = Stop timeOnly the counter is frozen
                                                 //         1h = Start timer

    MOV       r0, 0x00004102                     // TIMER5 is used to capture frequensy of TCLKIN with TIMER4 feedback signal.
    SBBO      r0, r13, OFFSET_TCLR, 4            // *(r13:DMTIMER5_BASE + OFFSET_TCLR) = r0:0x4102
                                                 //   0x48046038 : 0x00004102
                                                 //       0000 0000 0000 0000 0100 0001 0000 0010
                                                 // TCLR Register
                                                 //     31-15 RESERVED
                                                 //     14 GPO_CFG : General purpose output this register
                                                 //        drives directly the PORGPOCFG output pin
                                                 //         0h = PORGPOCFG drives 0 and configures the timer pin
                                                 //              as an output.
                                                 //       * 1h = PORGPOCFG drives 1 and configures the timer pin
                                                 //              as an input.
                                                 //     13 CAPT_MODE : Capture mode.
                                                 //       * 0h = Single capture
                                                 //         1h = Capture on second event
                                                 //     12 PT : Pulse or toggle mode on PORTIMERPWM output pin
                                                 //       * 0h = Pulse
                                                 //         1h = Toggle
                                                 //     11-10 TRG : Trigger output mode on PORTIMERPWM output pin
                                                 //       * 0h = No trigger
                                                 //         1h = Trigger on overflow
                                                 //         2h = Trigger on overflow and match
                                                 //         3h = Reserved
                                                 //     9-8 TCM : Transition Capture Mode on PIEVENTCAPT input pin
                                                 //         0h = No capture
                                                 //       * 1h = Capture on low to high transition
                                                 //         2h = Capture on high to low transition
                                                 //         3h = Capture on both edge transition
                                                 //     7 SCPWM : This bit should be set or clear while
                                                 //                    the timer is stopped or the trigger is off
                                                 //       * 0h = Clear the PORTIMERPWM output pin and select positive
                                                 //              pulse for pulse mode
                                                 //         1h = Set the PORTIMERPWM output pin and select negative
                                                 //              pulse for pulse mode
                                                 //     6 CE :
                                                 //       * 0h = Compare mode is disabled
                                                 //         1h = Compare mode is enabled
                                                 //     5 PRE : Prescaler enable
                                                 //       * 0h = The TIMER clock input pin clocks the counter
                                                 //         1h = The divided input pin clocks the counter
                                                 //     4-2 PTV : Pre-scale clock Timer value
                                                 //       * 0h = x2
                                                 //     1 AR :
                                                 //         0h = One shot timer
                                                 //       * 1h = Auto-reload timer
                                                 //     0 ST : In the case of one-shot mode selected (AR = 0),
                                                 //                 this bit is automatically reset by internal logic
                                                 //                 when the counter is overflowed.
                                                 //         0h (R) = Stop timeOnly the counter is frozen
                                                 //         1h = Start timer

    MOV       r0, 0x00001400                     // TIMER6 is used to make positive wave which divided TCLKIN by 2.
    SBBO      r0, r14, OFFSET_TCLR, 4            // *(r14:DMTIMER6_BASE + OFFSET_TCLR) = r0:0x00001400
                                                 //   0x48048038 : 0x00001400
                                                 //       0000 0000 0000 0000 0001 0100 0000 0000
                                                 // TCLR Register
                                                 //     31-15 RESERVED
                                                 //     14 GPO_CFG : General purpose output this register
                                                 //        drives directly the PORGPOCFG output pin
                                                 //       * 0h = PORGPOCFG drives 0 and configures the timer pin
                                                 //              as an output.
                                                 //         1h = PORGPOCFG drives 1 and configures the timer pin
                                                 //              as an input.
                                                 //     13 CAPT_MODE : Capture mode.
                                                 //       * 0h = Single capture
                                                 //         1h = Capture on second event
                                                 //     12 PT : Pulse or toggle mode on PORTIMERPWM output pin
                                                 //         0h = Pulse
                                                 //       * 1h = Toggle
                                                 //     11-10 TRG : Trigger output mode on PORTIMERPWM output pin
                                                 //         0h = No trigger
                                                 //       * 1h = Trigger on overflow
                                                 //         2h = Trigger on overflow and match
                                                 //         3h = Reserved
                                                 //     9-8 TCM : Transition Capture Mode on PIEVENTCAPT input pin
                                                 //       * 0h = No capture
                                                 //         1h = Capture on low to high transition
                                                 //         2h = Capture on high to low transition
                                                 //         3h = Capture on both edge transition
                                                 //     7 SCPWM : This bit should be set or clear while
                                                 //                    the timer is stopped or the trigger is off
                                                 //       * 0h = Clear the PORTIMERPWM output pin and select positive
                                                 //              pulse for pulse mode
                                                 //         1h = Set the PORTIMERPWM output pin and select negative
                                                 //              pulse for pulse mode
                                                 //     6 CE :
                                                 //       * 0h = Compare mode is disabled
                                                 //         1h = Compare mode is enabled
                                                 //     5 PRE : Prescaler enable
                                                 //       * 0h = The TIMER clock input pin clocks the counter
                                                 //         1h = The divided input pin clocks the counter
                                                 //     4-2 PTV : Pre-scale clock Timer value
                                                 //       * 0h = x2
                                                 //     1 AR :
                                                 //       * 0h = One shot timer
                                                 //         1h = Auto-reload timer
                                                 //     0 ST : In the case of one-shot mode selected (AR = 0),
                                                 //                 this bit is automatically reset by internal logic
                                                 //                 when the counter is overflowed.
                                                 //       * 0h (R) = Stop timeOnly the counter is frozen
                                                 //         1h = Start timer

    MOV       r0, 0x00001482                     // TIMER7 is used to make negative wave which divided TCLKIN by 2.
    SBBO      r0, r15, OFFSET_TCLR, 4            // *(r15:DMTIMER7_BASE + OFFSET_TCLR) = r0:0x00001482
                                                 //   0x4804a038 : 0x00001482
                                                 //       0000 0000 0000 0000 0001 0100 1000 0010
                                                 // TCLR Register
                                                 //     31-15 RESERVED R 0h
                                                 //     14 GPO_CFG : General purpose output this register
                                                 //        drives directly the PORGPOCFG output pin
                                                 //       * 0h = PORGPOCFG drives 0 and configures the timer pin
                                                 //              as an output.
                                                 //         1h = PORGPOCFG drives 1 and configures the timer pin
                                                 //              as an input.
                                                 //     13 CAPT_MODE : Capture mode.
                                                 //       * 0h = Single capture
                                                 //         1h = Capture on second event
                                                 //     12 PT : Pulse or toggle mode on PORTIMERPWM output pin
                                                 //         0h = Pulse
                                                 //       * 1h = Toggle
                                                 //     11-10 TRG : Trigger output mode on PORTIMERPWM output pin
                                                 //         0h = No trigger
                                                 //       * 1h = Trigger on overflow
                                                 //         2h = Trigger on overflow and match
                                                 //         3h = Reserved
                                                 //     9-8 TCM : Transition Capture Mode on PIEVENTCAPT input pin
                                                 //       * 0h = No capture
                                                 //         1h = Capture on low to high transition
                                                 //         2h = Capture on high to low transition
                                                 //         3h = Capture on both edge transition
                                                 //     7 SCPWM : This bit should be set or clear while
                                                 //                    the timer is stopped or the trigger is off
                                                 //         0h = Clear the PORTIMERPWM output pin and select positive
                                                 //              pulse for pulse mode
                                                 //       * 1h = Set the PORTIMERPWM output pin and select negative
                                                 //              pulse for pulse mode
                                                 //     6 CE :
                                                 //       * 0h = Compare mode is disabled
                                                 //         1h = Compare mode is enabled
                                                 //     5 PRE : Prescaler enable
                                                 //       * 0h = The TIMER clock input pin clocks the counter
                                                 //         1h = The divided input pin clocks the counter
                                                 //     4-2 PTV : Pre-scale clock Timer value
                                                 //       * 0h = x2
                                                 //     1 AR :
                                                 //         0h = One shot timer
                                                 //       * 1h = Auto-reload timer
                                                 //     0 ST : In the case of one-shot mode selected (AR = 0),
                                                 //                 this bit is automatically reset by internal logic
                                                 //                 when the counter is overflowed.
                                                 //         0h (R) = Stop timeOnly the counter is frozen
                                                 //       * 1h = Start timer

    // then we change clock sources for each TCRRs.
    // CLKSEL_TIMERx are in DPLL sub-system
    MOV       r0, 0x00000001                        //
    SBBO      r0, r11, OFFSET_CLKSEL_TIMER4_CLK, 4  // *(r11:CM_DPLL_BASE + OFFSET_CLKSEL_TIMER4_CLK) = r0:0x01
                                                    //   0x44E00510 : 0x00000001
                                                    // CLKSEL Register
                                                    //     31-2 Reserved
                                                    //     1-0 CLKSEL : Selects the Mux select line for TIMERx
                                                    //                clock [warm reset insensitive]
                                                    //         0x0 = SEL1 : Select TCLKIN clock
                                                    //       * 0x1 = SEL2 : Select CLK_M_OSC clock
                                                    //         0x2 = SEL3 : Select CLK_32KHZ clock
                                                    //         0x3 = SEL4 : Reserved
    SBBO      r17, r11, OFFSET_CLKSEL_TIMER5_CLK, 4 // *(r11:CM_DPLL_BASE + OFFSET_CLKSEL_TIMER5_CLK) = r17:0x00
                                                    //   0x44E00518 : 0x00000001
    SBBO      r17, r11, OFFSET_CLKSEL_TIMER6_CLK, 4 // *(r11:CM_DPLL_BASE + OFFSET_CLKSEL_TIMER6_CLK) = r17:0x00
                                                    //   0x44E0051c : 0x00000000
    SBBO      r17, r11, OFFSET_CLKSEL_TIMER7_CLK, 4 // *(r11:CM_DPLL_BASE + OFFSET_CLKSEL_TIMER7_CLK) = r17:0x00
                                                    //   0x44E00504 : 0x00000000
                                                    // CLKSEL Register
                                                    //     31-2 Reserved
                                                    //     1-0 CLKSEL : Selects the Mux select line for TIMERx
                                                    //                clock [warm reset insensitive]
                                                    //       * 0x0 = SEL1 : Select TCLKIN clock
                                                    //         0x1 = SEL2 : Select CLK_M_OSC clock
                                                    //         0x2 = SEL3 : Select CLK_32KHZ clock
                                                    //         0x3 = SEL4 : Reserved

    // we set TLDRs
    MOV       r0, 0xffffffff - 1200000 + 1       // target frequency is 10Hz
    SBBO      r0, r12, OFFSET_TLDR, 4            // *(r12:DMTIMER4_BASE + OFFSET_TLDR) = r0:
                                                 //   0x48044040 :
    SBBO      r17, r13, OFFSET_TLDR, 4           // *(r13:DMTIMER5_BASE + OFFSET_TLDR) = r17:0x0
                                                 //   0x48046040 : 0x00000000
    MOV       r0, 0xfffffffe                     //
    SBBO      r0, r14, OFFSET_TLDR, 4            // *(r14:DMTIMER6_BASE + OFFSET_TLDR) = r0:0xfffffffe
                                                 //   0x48047040 : 0xfffffffe
    SBBO      r0, r15, OFFSET_TLDR, 4            // *(r15:DMTIMER7_BASE + OFFSET_TLDR) = r0:0xfffffffe
                                                 //   0x4804a040 : 0xfffffffe
                                                 // TLDR Register
                                                 //     31-0 LOAD_VALUE : Timer counter value loaded
                                                 //          on overflow in auto-reload mode or on TTGR write access

    // we set TCRRs to initial values as same value with TLDR
    MOV       r0, 0xffffffff - 1200000 + 1       // target frequency is 10Hz
    SBBO      r0, r12, OFFSET_TCRR, 4            // *(r12:DMTIMER4_BASE + OFFSET_TCRR) = r0:
                                                 //   0x4804403c :
    SBBO      r17, r13, OFFSET_TCRR, 4           // *(r13:DMTIMER5_BASE + OFFSET_TCRR) = r17:0x0
                                                 //   0x4804603c : 0x00000000
    MOV       r0, 0xfffffffe                     //
    SBBO      r0, r14, OFFSET_TCRR, 4            // *(r14:DMTIMER6_BASE + OFFSET_TCRR) = r0:0xfffffffe
                                                 //   0x4804703c : 0xfffffffe
    SBBO      r0, r15, OFFSET_TCRR, 4            // *(r15:DMTIMER7_BASE + OFFSET_TCRR) = r0:0xfffffffe
                                                 //   0x4804a03c : 0xfffffffe
                                                 // TCRR Register
                                                 //     31-0 TIMER_COUNTER R/W 0h Value of TIMER counter

    // we clear TCAR1s and TCAR2s
    SBBO      r17, r12, OFFSET_TCAR1, 4          // *(r12:DMTIMER4_BASE + OFFSET_TCAR1) = r17:0x00000000
                                                 //   0x48044050 : 0x00000000
    SBBO      r17, r13, OFFSET_TCAR1, 4          // *(r13:DMTIMER5_BASE + OFFSET_TCAR1) = r17:0x00000000
                                                 //   0x48046050 : 0x00000000
    SBBO      r17, r14, OFFSET_TCAR1, 4          // *(r14:DMTIMER6_BASE + OFFSET_TCAR1) = r17:0x00000000
                                                 //   0x48047050 : 0x00000000
    SBBO      r17, r15, OFFSET_TCAR1, 4          // *(r15:DMTIMER7_BASE + OFFSET_TCAR1) = r17:0x00000000
                                                 //   0x4804a050 : 0x00000000
                                                 // TCAR1 Register
                                                 //     31-0 CAPTURED_VALUE : Timer counter value
                                                 //          captured on an external event trigger

    SBBO      r17, r12, OFFSET_TCAR2, 4          // *(r12:DMTIMER4_BASE + OFFSET_TCAR2) = r17:0x00000000
                                                 //   0x48044058 : 0x00000000
    SBBO      r17, r13, OFFSET_TCAR2, 4          // *(r13:DMTIMER5_BASE + OFFSET_TCAR2) = r17:0x00000000
                                                 //   0x48046058 : 0x00000000
    SBBO      r17, r14, OFFSET_TCAR2, 4          // *(r14:DMTIMER6_BASE + OFFSET_TCAR2) = r17:0x00000000
                                                 //   0x48047058 : 0x00000000
    SBBO      r17, r15, OFFSET_TCAR2, 4          // *(r15:DMTIMER7_BASE + OFFSET_TCAR2) = r17:0x00000000
                                                 //   0x4804a058 : 0x00000000
                                                 // TCAR2 Register
                                                 //     31-0 CAPTURED_VALUE : Timer counter value
                                                 //          captured on an external event trigger

    MOV       r0, 0x0000007                      //
    SBBO      r0, r12, OFFSET_IRQENABLE_CLR, 4   // *(r12:DMTIMER4_BASE + OFFSET_IRQENABLE_CLR) = r0:0x07
                                                 //   0x48044030 : 0x07
    SBBO      r0, r13, OFFSET_IRQENABLE_CLR, 4   // *(r13:DMTIMER5_BASE + OFFSET_IRQENABLE_CLR) = r0:0x07
                                                 //   0x48046030 : 0x07
    SBBO      r0, r14, OFFSET_IRQENABLE_CLR, 4   // *(r14:DMTIMER6_BASE + OFFSET_IRQENABLE_CLR) = r0:0x07
                                                 //   0x48047030 : 0x07
    SBBO      r0, r15, OFFSET_IRQENABLE_CLR, 4   // *(r15:DMTIMER7_BASE + OFFSET_IRQENABLE_CLR) = r0:0x07
                                                 //   0x4804a030 : 0x07
                                                 // IRQENABLE_CLR Register
                                                 //     31-3 RESERVED R 0h
                                                 //     2 TCAR_EN_FLAG : IRQ enable for Capture
                                                 //        0h = IRQ event is disabled
                                                 //        1h = Clear IRQ enable
                                                 //     1 OVF_EN_FLAG : IRQ enable for Overflow
                                                 //        0h = IRQ event is disabled
                                                 //        1h = Clear IRQ enable
                                                 //     0 MAT_EN_FLAG : IRQ enable for Match
                                                 //        0h = IRQ event is disabled
                                                 //        1h = Clear IRQ enable

    MOV       r0, 0x00000004                     //
    SBBO      r0, r13, OFFSET_IRQENABLE_SET, 4   // *(r13:DMTIMER5_BASE + OFFSET_IRQENABLE_SET) = r0:0x04
                                                 //   0x4804602c : 0x00000004
    MOV       r0, 0x00000002                     //
    SBBO      r0, r14, OFFSET_IRQENABLE_SET, 4   // *(r14:DMTIMER6_BASE + OFFSET_IRQENABLE_SET) = r0:0x02
                                                 //   0x4804702c : 0x00000002
                                                 // IRQENABLE_SET Register
                                                 //     31-3 RESERVED
                                                 //     2 TCAR_EN_FLAG : IRQ enable for Capture
                                                 //        0h = IRQ event is disabled
                                                 //        1h = IRQ event is enabled
                                                 //     1 OVF_EN_FLAG : IRQ enable for Overflow
                                                 //        0h = IRQ event is disabled
                                                 //        1h = IRQ event is enabled
                                                 //     0 MAT_EN_FLAG : IRQ enable for Match
                                                 //        0h = IRQ event is disabled
                                                 //        1h = IRQ event is enabled

    MOV       r0, 0x00000007                     //
    SBBO      r0, r12, OFFSET_IRQSTATUS, 4       // *(r12:DMTIMER4_BASE + OFFSET_IRQSTATUS) = r0:0x00000007
                                                 //   0x48044028 : 0x00000007
    SBBO      r0, r13, OFFSET_IRQSTATUS, 4       // *(r13:DMTIMER5_BASE + OFFSET_IRQSTATUS) = r0:0x00000007
                                                 //   0x48046028 : 0x00000007
    SBBO      r0, r14, OFFSET_IRQSTATUS, 4       // *(r14:DMTIMER6_BASE + OFFSET_IRQSTATUS) = r0:0x00000007
                                                 //   0x48047028 : 0x00000007
    SBBO      r0, r15, OFFSET_IRQSTATUS, 4       // *(r15:DMTIMER7_BASE + OFFSET_IRQSTATUS) = r0:0x00000007
                                                 //   0x4804a028 : 0x00000007
                                                 // IRQSTATUS Register
                                                 //     31-3 RESERVED
                                                 //     2 TCAR_IT_FLAG : IRQ status for Capture
                                                 //        0h = No event pending
                                                 //        1h = IRQ event pending
                                                 //     1 OVF_IT_FLAG : IRQ status for Overflow
                                                 //        0h = No event pending
                                                 //        1h = IRQ event pending
                                                 //     0 MAT_IT_FLAG : IRQ status for Match
                                                 //        0h = No event pending
                                                 //        1h = IRQ event pending

// we start TIMER4 as 1Hz signal wave output
    MOV       r0, 0x00001403                     // TIMER4 is used to make 10Hz clock out.
    SBBO      r0, r12, OFFSET_TCLR, 4            // *(r12:DMTIMER4_BASE + OFFSET_TCLR) = r0:0x00001403
                                                 //   0x48044038 : 0x00001403
                                                 //       0000 0000 0000 0000 0001 0100 0000 0011
                                                 // TCLR Register
                                                 //     0 ST : In the case of one-shot mode selected (AR = 0),
                                                 //                 this bit is automatically reset by internal logic
                                                 //                 when the counter is overflowed.
                                                 //         0h (R) = Stop timeOnly the counter is frozen
                                                 //       * 1h = Start timer

    MOV       r0, 1                              // it means notification &quot;WAITING 1st INTERRUPT&quot;
    SBCO      r0, CONST_PRUSHAREDRAM, 0x00, 4    // *(CONST_PRUSHAREDRAM + 0) = r0:0x00000001
    MOV       r31.b0, PRU0_ARM_INTERRUPT+16      // we send notification to Host

// we start TIMER6 as one-shot timer for phase syncronization between TIMER6 and TIMER7.
    MOV       r3, 0x00001403                     // TCLR in TIMER6 value to re-start TIMER6
    MOV       r4, 0x00001483                     // TCLR in TIMER7 value to start TIMER7
    MOV       r0, 0x00001401                     // TIMER6 is used to divide TCLKIN frequency by 4 as one-shot timer
    SBBO      r0, r14, OFFSET_TCLR, 4            // *(r14:DMTIMER6_BASE + OFFSET_TCLR) = r0:0x00001401
                                                 //   0x48048038 : 0x00001401
                                                 //       0000 0000 0000 0000 0001 0100 0000 0001
                                                 // TCLR Register
                                                 //     0 ST : In the case of one-shot mode selected (AR = 0),
                                                 //                 this bit is automatically reset by internal logic
                                                 //                 when the counter is overflowed.
                                                 //         0h (R) = Stop timeOnly the counter is frozen
                                                 //       * 1h = Start timer

// start timing of timer may compete with level transition of TCLKIN as race condition.
// in order to synchronize phase between TIMER6 and TIMER7, we re-start TIMER6 and start TIMER7 with TIMER6 OVF timing.
// since TIMER6 has started as one-shot, TIMER6 will stop automatically when OVF is occurred.

WAIT_TIMER6_1ST_OVF:
    // we wait for OVF_IT_FLAG of TIMER6 to be set
    LBBO      r0, r14, OFFSET_IRQSTATUS, 4       // r0 = *(r14:DMTIMER6_BASE + OFFSET_IRQSTATUS)
                                                 //   0x48047028 :
    AND       r0, r0, 0x02                       //
    QBEQ      WAIT_TIMER6_1ST_OVF, r0, 0x00      // if (r0 &amp;amp;amp;amp;amp;amp; 0x02) == 0x00 then goto WAIT_TIMER6_1ST_OVF

    // re-start both TIMER6 and TIMER7
    // TIMER6 is used to make positive phase wave which divided TCLKIN by 4.
    SBBO      r3, r14, OFFSET_TCLR, 4            // *(r14:DMTIMER6_BASE + OFFSET_TCLR) = r3:0x00001403
    // TIMER7 is used to make negative phase wave which divided TCLKIN by 4.
    SBBO      r4, r15, OFFSET_TCLR, 4            // *(r15:DMTIMER7_BASE + OFFSET_TCLR) = r4:0x00001483

    // since interrupt of TIMER6 has served, we disable TIMER6 OVF interrupt.
    MOV       r0, 0x00000007                     //
    SBBO      r0, r14, OFFSET_IRQENABLE_CLR, 4   // *(r14:DMTIMER6_BASE + OFFSET_IRQENABLE_CLR) = r0:0x07
                                                 //   0x48047030 : 0x07
    SBBO      r0, r14, OFFSET_IRQSTATUS, 4       // *(r14:DMTIMER6_BASE + OFFSET_IRQSTATUS) = r0:0x00000007
                                                 //   0x48047028 : 0x00000007

    MOV       r0, 2                              // it means notification &quot;START CAPTURE&quot;
    SBCO      r0, CONST_PRUSHAREDRAM, 0x00, 4    // *(CONST_PRUSHAREDRAM + 0) = r0:0x00000002
    MOV       r31.b0, PRU0_ARM_INTERRUPT+16      // we send notification to Host

// we start TIMER5
    MOV       r4, r17                            // we initialize r4:previus_CAP_value with r17:0x000000000.
    MOV       r0, 0x00004103                     // TIMER5 is used to capture frequensy of TCLKIN using feedback TIMER4 signal.
    SBBO      r0, r13, OFFSET_TCLR, 4            // *(r13:DMTIMER5_BASE + OFFSET_TCLR) = r0:0x4103
                                                 //   0x44E00518 : 0x00004103
                                                 //       0000 0000 0000 0000 0100 0001 0000 0011
                                                 // TCLR Register
                                                 //     0 ST : In the case of one-shot mode selected (AR = 0),
                                                 //                 this bit is automatically reset by internal logic
                                                 //                 when the counter is overflowed.
                                                 //         0h (R) = Stop timeOnly the counter is frozen
                                                 //       * 1h = Start timer

CAPTURE_LOOP:
    // we wait for TCAR_IT_FLAG of TIMER5 to be set
    LBBO      r0, r13, OFFSET_IRQSTATUS, 4       // r0 = *(r13:DMTIMER6_BASE + OFFSET_IRQSTATUS)

    QBEQ      CAPTURE_LOOP, r0, 0x00             // if (r0 &amp;amp;amp;amp;amp;amp; 0x04) == 0x00 then goto CAPTURE_LOOP

    // we clear all interrupt flsgs
    MOV       r1, 0x07                           //
    SBBO      r1, r13, OFFSET_IRQSTATUS, 4       // *(r13:DMTIMER5_BASE + OFFSET_IRQSTATUS) = r1:0x00000007
                                                 //   0x48046028 :
    AND       r0, r0, 0x04                       //
    QBEQ      CAPTURE_LOOP, r0, 0x00             // if (r0 &amp;amp;amp;amp;amp;amp; 0x04) == 0x00 then goto CAPTURE_LOOP

WAIT_CAPTUER:
    LBBO      r0, r13, OFFSET_TCAR1, 4           // r0 = *(r13:DMTIMER5_BASE + OFFSET_TCAR1)
                                                 //   0x48046050 : 0x00000000
    QBEQ      WAIT_CAPTUER, r0, r4               // if r0:current_capture == r4:previous_capture
                                                 //    then goto CAPTURE_LOOP
                                                 // in my investigation, in order to capture the TCRR into TCAR1,
                                                 // more tclkin clocks are required after TCAR_IT_FLAG is set. 

    SUB       r1, r0, r4                         //
    SBCO      r1, CONST_PRUSHAREDRAM, 0x04, 4    // *(CONST_PRUSHAREDRAM + 4) = r1

    MOV       r4, r0                             // update r4:previus_CAP_value with r0:new_CAPTURE value

    MOV       r0, 3                              // it means notification &quot;CAPTUERED&quot; to host
    SBCO      r0, CONST_PRUSHAREDRAM, 0x00, 4    // *(CONST_PRUSHAREDRAM + 0) = r0:0x00000003
    MOV       r31.b0, PRU0_ARM_INTERRUPT+16      // we send notification to Host

    JMP       CAPTURE_LOOP

同じくPRUのincludeファイル。

// dtimer.hp

#ifndef _PRU_PWM_
#define _PRU_PWM_

// ***************************************
// *      Global Macro definitions       *
// ***************************************

#define PRU0_PRU1_INTERRUPT     17
#define PRU1_PRU0_INTERRUPT     18
#define PRU0_ARM_INTERRUPT      19
#define PRU1_ARM_INTERRUPT      20
#define ARM_PRU0_INTERRUPT      21
#define ARM_PRU1_INTERRUPT      22

#define CONST_PRUCFG	        C4
#define CONST_PRUD0RAM          C24
#define CONST_PRUD1RAM          C25
#define CONST_PRUSHAREDRAM      C28
#define CONST_DDR               C31

#define PRU0_CTRL_REG_BASE    0x00022000

#define OFFSET_PRU_CONTROL_REG        0x00
#define OFFSET_PRU_STATUS_REG         0x04
                                              // 5 SUB_MWAIT
                                              //     Status bit for wait state.
                                              //       0 = Ready for Transaction
                                              //       1 = Wait until 0
                                              // 4   STANDBY_INIT
                                              //       1 = Initiate standby sequence.
                                              //       0 = Ready for Transaction
                                              // 3-2 STANDBY_MODE
                                              //       0h = Force standby mode: Initiator unconditionally
                                              //            in standby (standby = 1).
                                              //       1h = No standby mode: Initiator unconditionally out
                                              //            of standby (standby = 0).
                                              //       2h = Smart standby mode: Standby requested by initiator
                                              //            depending on internal conditions.
                                              //       3h = Reserved.
                                              // 1-0 IDLE_MODE
                                              //       0h = Force-idle mode.
                                              //       1h = No-idle mode.
                                              //       2h = Smart-idle mode.
                                              //       3h = Reserved.
#define OFFSET_PRU_WAKEUP_EN_REG      0x08
#define OFFSET_PRU_CYCLE_REG          0x0C
#define OFFSET_PRU_STALL_REG          0x10
#define OFFSET_PRU_CTBIR0_REG         0x20
                                               // 23-16 C25_BLK_INDEX (PRU1/0 Local Data)
                                               // 7-0   C24_BLK_INDEX (PRU0/1 Local Data)
#define OFFSET_PRU_CTBIR1_REG         0x24
                                               // 23-16 C27_BLK_INDEX (MII_RT (local))
                                               // 7-0   C26_BLK_INDEX (IEP (local))
#define OFFSET_PRU_CTPPR0_REG         0x28
                                               // 31-16 C29_POINTER (TPCC)
                                               // 15-0  C28_POINTER (Shared PRU RAM (local))
#define OFFSET_PRU_CTPPR1_REG         0x2C
                                               // 31-16 C31_POINTER (EMIF0 DDR Base)
                                               // 15-0  C30_POINTER (L3 OCMC0)

#define PRU_ICSS_CFG_REG_BASE 0x00026000
#define OFFSET_CFG_REVID_REG          0x00
#define OFFSET_CFG_SYSCFG_REG         0x04
                                               // 5 SUB_MWAIT
                                               //     Status bit for wait state.(Read only)
                                               //       0 = Ready for Transaction
                                               //       1 = Wait until 0
                                               // 4 STANDBY_INIT
                                               //       1 = Initiate standby sequence.
                                               //       0 = Enable OCP master ports.
                                               // 3-2 STANDBY_MODE
                                               //       0h = Force standby mode: Initiator unconditionally
                                               //            in standby (standby = 1).
                                               //       1h = No standby mode: Initiator unconditionally out
                                               //            of standby (standby = 0).
                                               //       2h = Smart standby mode: Standby requested by initiator
                                               //            depending on internal conditions.
                                               //       3h = Reserved.
                                               // 1-0 IDLE_MODE
                                               //       0h = Force-idle mode.
                                               //       1h = No-idle mode.
                                               //       2h = Smart-idle mode.
                                               //       3h = Reserved.
#define OFFSET_CFG_GPCFG0_REG         0x08
                                               // 25 PRU0_GPO_SH_SEL
                                               //     Defines which shadow register is currently getting used
                                               //     for GPO shifting.(Read only)
                                               //       0 = gpo_sh0 is selected
                                               //       1 = gpo_sh1 is selected
                                               // 24-20 PRU0_GPO_DIV1
                                               //     Divisor value (divide by PRU0_GPO_DIV1 + 1).
                                               //       0h = div 1.0.
                                               //       1h = div 1.5.
                                               //       2h = div 2.0.
                                               //         ..
                                               //       1eh = div 16.0.
                                               //       1fh = reserved.
                                               // 19-15 PRU0_GPO_DIV0
                                               //     Same as PRU0_GPO_DIV1
                                               // 14 PRU0_GPO_MODE
                                               //       0 = Direct output mode
                                               //       1 = Serial output mode
                                               // 13 PRU0_GPI_SB
                                               //     Start Bit event for 28-bit shift mode.
                                               //     PRU0_GPI_SB (pru0_r31_status[29]) is set when first capture
                                               //     of a 1 on pru0_r31_status[0].
                                               //       Read 1: Start Bit event occurred.
                                               //       Read 0: Start Bit event has not occurred.
                                               //       Write 1: Will clear PRU0_GPI_SB and clear the whole
                                               //                shift register.
                                               //       Write 0: No Effect.
                                               // 12-8 PRU0_GPI_DIV1
                                               //     Divisor value (divide by PRU0_GPI_DIV1 + 1).
                                               //       0h = div 1.0.
                                               //       1h = div 1.5.
                                               //       2h = div 2.0.
                                               //         ..
                                               //       1eh = div 16.0.
                                               //       1fh = reserved.
                                               // 7-3  PRU0_GPI_DIV0
                                               //     Same as PRU0_GPI_DIV1
                                               // 2 PRU0_GPI_CLK_MODE
                                               //     Parallel 16-bit capture mode clock edge.
                                               //       0 = Use the positive edge of pru0_r31_status[16]
                                               //       1 = Use the negative edge of pru0_r31_status[16]
                                               // 1-0 PRU0_GPI_MODE
                                               //       0h = Direct connection mode.
                                               //       1h = 16-bit parallel capture mode.
                                               //       2h = 28-bit shift mode.
                                               //       3h = Mii_rt mode.
#define OFFSET_CFG_GPCFG1_REG         0x0C
                                               // Fields are Same as GPCFG0_REG, buf GPCFG1_REG is for PRU1.

#define OFFSET_CFG_CGR_REG            0x10
#define OFFSET_CFG_ISRP_REG           0x14
#define OFFSET_CFG_ISP_REG            0x18
#define OFFSET_CFG_IESP_REG           0x1C
#define OFFSET_CFG_IECP_REG           0x20
#define OFFSET_CFG_PMAO_REG           0x28
#define OFFSET_CFG_MII_RT_REG         0x2C
#define OFFSET_CFG_IEPCLK_REG         0x30
#define OFFSET_CFG_SPP_REG            0x34
#define OFFSET_CFG_PIN_MX_REG         0x40

// Address for the Constant table Block Index Register (CTBIR)
#define CTBIR          0x22020

// Address for the Constant table Programmable Pointer Register 0(CTPPR_0)
#define CTPPR_0         0x22028

// Address for the Constant table Programmable Pointer Register 1(CTPPR_1)
#define CTPPR_1         0x2202C

// CM_PER related registers define
#define CM_PER_BASE    0x44E00000    // Clock Module Peripheral Registers

#define OFFSET_CM_PER_L4LS_CLKSTCTRL       0x000
#define OFFSET_CM_PER_L3S_CLKSTCTRL        0x004
#define OFFSET_CM_PER_L3_CLKSTCTRL         0x00C
#define OFFSET_CM_PER_CPGMAC0_CLKCTRL      0x014
#define OFFSET_CM_PER_LCDC_CLKCTRL         0x018
#define OFFSET_CM_PER_USB0_CLKCTRL         0x01C
#define OFFSET_CM_PER_TPTC0_CLKCTRL        0x024
#define OFFSET_CM_PER_EMIF_CLKCTRL         0x028
#define OFFSET_CM_PER_OCMCRAM_CLKCTRL      0x02C
#define OFFSET_CM_PER_GPMC_CLKCTRL         0x030
#define OFFSET_CM_PER_MCASP0_CLKCTRL       0x034
#define OFFSET_CM_PER_UART5_CLKCTRL        0x038
#define OFFSET_CM_PER_MMC0_CLKCTRL         0x03C
#define OFFSET_CM_PER_ELM_CLKCTRL          0x040
#define OFFSET_CM_PER_I2C2_CLKCTRL         0x044
#define OFFSET_CM_PER_I2C1_CLKCTRL         0x048
#define OFFSET_CM_PER_SPI0_CLKCTRL         0x04C
#define OFFSET_CM_PER_SPI1_CLKCTRL         0x050
#define OFFSET_CM_PER_L4LS_CLKCTRL         0x060
#define OFFSET_CM_PER_MCASP1_CLKCTRL       0x068
#define OFFSET_CM_PER_UART1_CLKCTRL        0x06C
#define OFFSET_CM_PER_UART2_CLKCTRL        0x070
#define OFFSET_CM_PER_UART3_CLKCTRL        0x074
#define OFFSET_CM_PER_UART4_CLKCTRL        0x078
#define OFFSET_CM_PER_TIMER7_CLKCTRL       0x07C        // timer7
#define OFFSET_CM_PER_TIMER2_CLKCTRL       0x080
#define OFFSET_CM_PER_TIMER3_CLKCTRL       0x084
#define OFFSET_CM_PER_TIMER4_CLKCTRL       0x088        // timer4
#define OFFSET_CM_PER_GPIO1_CLKCTRL        0x0AC
#define OFFSET_CM_PER_GPIO2_CLKCTRL        0x0B0
#define OFFSET_CM_PER_GPIO3_CLKCTRL        0x0B4
#define OFFSET_CM_PER_TPCC_CLKCTRL         0x0BC
#define OFFSET_CM_PER_DCAN0_CLKCTRL        0x0C0
#define OFFSET_CM_PER_DCAN1_CLKCTRL        0x0C4
#define OFFSET_CM_PER_EPWMSS1_CLKCTRL      0x0CC        // epwmss1
#define OFFSET_CM_PER_EPWMSS0_CLKCTRL      0x0D4        // epwmss0
#define OFFSET_CM_PER_EPWMSS2_CLKCTRL      0x0D8        // epwmss2
#define OFFSET_CM_PER_L3_INSTR_CLKCTRL     0x0DC
#define OFFSET_CM_PER_L3_CLKCTRL           0x0E0
#define OFFSET_CM_PER_IEEE5000_CLKCTRL     0x0E4
#define OFFSET_CM_PER_PRU_ICSS_CLKCTRL     0x0E8        // pru_icss
#define OFFSET_CM_PER_TIMER5_CLKCTRL       0x0EC        // timer5
#define OFFSET_CM_PER_TIMER6_CLKCTRL       0x0F0        // timer6
#define OFFSET_CM_PER_MMC1_CLKCTRL         0x0F4
#define OFFSET_CM_PER_MMC2_CLKCTRL         0x0F8
#define OFFSET_CM_PER_TPTC1_CLKCTRL        0x0FC
#define OFFSET_CM_PER_TPTC2_CLKCTRL        0x100
#define OFFSET_CM_PER_SPINLOCK_CLKCTRL     0x10C
#define OFFSET_CM_PER_MAILBOX0_CLKCTRL     0x110
#define OFFSET_CM_PER_L4HS_CLKSTCTRL       0x11C
#define OFFSET_CM_PER_L4HS_CLKCTRL         0x120
#define OFFSET_CM_PER_OCPWP_L3_CLKSTCTRL   0x12C
#define OFFSET_CM_PER_OCPWP_CLKCTRL        0x130
#define OFFSET_CM_PER_PRU_ICSS_CLKSTCTRL   0x140       // pru_icss_clk
#define OFFSET_CM_PER_CPSW_CLKSTCTRL       0x144
#define OFFSET_CM_PER_LCDC_CLKSTCTRL       0x148
#define OFFSET_CM_PER_CLKDIV32K_CLKCTRL    0x14C
#define OFFSET_CM_PER_CLK_24MHZ_CLKSTCTRL  0x150 

// CM_DPLL related registers define
#define CM_DPLL_BASE                   0x44E00500    // Clock Module PLL Registers

#define OFFSET_CLKSEL_TIMER7_CLK       0x04   // Selects the Mux select line for TIMER7 clock
#define OFFSET_CLKSEL_TIMER2_CLK       0x08   // Selects the Mux select line for TIMER2 clock
#define OFFSET_CLKSEL_TIMER3_CLK       0x0C   // Selects the Mux select line for TIMER3 clock
#define OFFSET_CLKSEL_TIMER4_CLK       0x10   // Selects the Mux select line for TIMER4 clock
#define OFFSET_CM_MAC_CLKSEL           0x14   // Selects the clock divide ration for MII clock
#define OFFSET_CLKSEL_TIMER5_CLK       0x18   // Selects the Mux select line for TIMER5 clock
#define OFFSET_CLKSEL_TIMER6_CLK       0x1C   // Selects the Mux select line for TIMER6 clock
#define OFFSET_ CM_CPTS_RFT_CLKSEL     0x20   // Selects the Mux select line for CPTS RFT clock
#define OFFSET_CLKSEL_TIMER1MS_CLK     0x28   // Selects the Mux select line for TIMER1 clock
#define OFFSET_CLKSEL_GFX_FCLK         0x2C   // Selects the divider value for GFX clock
#define OFFSET_CLKSEL_PRU_ICSS_OCP_CLK 0x30   // Controls the Mux select line for PRU-ICSS OCP clock
#define OFFSET_CLKSEL_LCDC_PIXEL_CLK   0x34   // Controls the Mux select line for LCDC PIXEL clock
#define OFFSET_CLKSEL_WDT1_CLK         0x38   // Selects the Mux select line for Watchdog1 clock
#define OFFSET_CLKSEL_GPIO0_DBCLK      0x3C   // Selects the Mux select line for GPIO0 debounce clock

// PWMSS related registers define
#define PWM_Subsystem_0_BASE           0x48300000   // PWMSS0 Configuration Registers
#define PWM_Subsystem_1_BASE           0x48302000   // PWMSS1 Configuration Registers
#define PWM_Subsystem_2_BASE           0x48304000   // PWMSS2 Configuration Registers

#define OFFSET_IDVER                   0x00    // IDVER IP Revision Register
#define OFFSET_SYSCONFIG               0x04    // SYSCONFIG System Configuration Register Section 15.1.2.2
#define OFFSET_CLKCONFIG               0x08    // CLKCONFIG Clock Configuration Register Section 15.1.2.3
#define OFFSET_CLKSTATUS               0x0C    // CLKSTATUS Clock Status Register Section 15.1.2.4

// ePWM related registers define
#define ePWM0_BASE                     0x48300200  // PWMSS ePWM0 Registers
#define ePWM1_BASE                     0x48302200  // PWMSS ePWM1 Registers
#define ePWM2_BASE                     0x48304200  // PWMSS ePWM2 Registers

#define OFFSET_TBCTL                   0x00      // TBCTL Time-Base Control Register Section 15.2.4.1
#define OFFSET_TBSTS                   0x02      // TBSTS Time-Base Status Register Section 15.2.4.2
#define OFFSET_TBPHSHR                 0x04      // TBPHSHR Extension for HRPWM Phase Register Section 15.2.4.3
#define OFFSET_TBPHS                   0x06      // TBPHS Time-Base Phase Register Section 15.2.4.4
#define OFFSET_TBCNT                   0x08      // TBCNT Time-Base Counter Register Section 15.2.4.5
#define OFFSET_TBPRD                   0x0A      // TBPRD Time-Base Period Register Section 15.2.4.6
#define OFFSET_CMPCTL                  0x0E      // CMPCTL Counter-Compare Control Register Section 15.2.4.7
#define OFFSET_CMPAHR                  0x10      // CMPAHR Extension for HRPWM Counter-Compare A Register Section 15.2.4.8
#define OFFSET_CMPA                    0x12      // CMPA Counter-Compare A Register Section 15.2.4.9
#define OFFSET_CMPB                    0x14      // CMPB Counter-Compare B Register Section 15.2.4.10
#define OFFSET_AQCTLA                  0x16      // AQCTLA Action-Qualifier Control Register for Output A (EPWMxA) Section 15.2.4.11
#define OFFSET_AQCTLB                  0x18      // AQCTLB Action-Qualifier Control Register for Output B (EPWMxB) Section 15.2.4.12
#define OFFSET_AQSFRC                  0x1A      // AQSFRC Action-Qualifier Software Force Register Section 15.2.4.13
#define OFFSET_AQCSFRC                 0x1C      // AQCSFRC Action-Qualifier Continuous S/W Force Register Set Section 15.2.4.14
#define OFFSET_DBCTL                   0x1E      // DBCTL Dead-Band Generator Control Register Section 15.2.4.15
#define OFFSET_DBRED                   0x20      // DBRED Dead-Band Generator Rising Edge Delay Count Register Section 15.2.4.16
#define OFFSET_DBFED                   0x22      // DBFED Dead-Band Generator Falling Edge Delay Count Register Section 15.2.4.17
#define OFFSET_TZSEL                   0x24      // TZSEL Trip-Zone Select Register Section 15.2.4.18
#define OFFSET_TZCTL                   0x28      // TZCTL Trip-Zone Control Register Section 15.2.4.19
#define OFFSET_TZEINT                  0x2A      // TZEINT Trip-Zone Enable Interrupt Register Section 15.2.4.20
#define OFFSET_TZFLG                   0x2C      // TZFLG Trip-Zone Flag Register Section 15.2.4.21
#define OFFSET_TZCLR                   0x2E      // TZCLR Trip-Zone Clear Register Section 15.2.4.22
#define OFFSET_TZFRC                   0x30      // TZFRC Trip-Zone Force Register Section 15.2.4.23
#define OFFSET_ETSEL                   0x32      // ETSEL Event-Trigger Selection Register Section 15.2.4.24
#define OFFSET_ETPS                    0x34      // ETPS Event-Trigger Pre-Scale Register Section 15.2.4.25
#define OFFSET_ETFLG                   0x36      // ETFLG Event-Trigger Flag Register Section 15.2.4.26
#define OFFSET_ETCLR                   0x38      // ETCLR Event-Trigger Clear Register Section 15.2.4.27
#define OFFSET_ETFRC                   0x3A      // ETFRC Event-Trigger Force Register Section 15.2.4.28
#define OFFSET_PCCTL                   0x3C      // PCCTL PWM-Chopper Control Register Section 15.2.4.29
#define OFFSET_HRCNFG                  0xC0      // HRCNFG HRPWM configuration register (HRCNFG) Section 15.2.4.30

// eCAP related registers define

#define eCAP0_BASE                     0x48300100  // PWMSS eCAP0 Registers
#define eCAP1_BASE                     0x48302100  // PWMSS eCAP1 Registers
#define eCAP2_BASE                     0x48304100  // PWMSS eCAP2 Registers

#define OFFSET_TSCTR                   0x00    // TSCTR Time-Stamp Counter Register Section 15.3.4.1.1
#define OFFSET_CTRPHS                  0x04    // CTRPHS Counter Phase Offset Value Register Section 15.3.4.1.2
#define OFFSET_CAP1                    0x08    // CAP1 Capture 1 Register Section 15.3.4.1.3
#define OFFSET_CAP2                    0x0C    // CAP2 Capture 2 Register Section 15.3.4.1.4
#define OFFSET_CAP3                    0x10    // CAP3 Capture 3 Register Section 15.3.4.1.5
#define OFFSET_CAP4                    0x14    // CAP4 Capture 4 Register Section 15.3.4.1.6
#define OFFSET_ECCTL1                  0x28    // ECCTL1 Capture Control Register 1 Section 15.3.4.1.7
#define OFFSET_ECCTL2                  0x2A    // ECCTL2 Capture Control Register 2 Section 15.3.4.1.8
#define OFFSET_ECEINT                  0x2C    // ECEINT Capture Interrupt Enable Register Section 15.3.4.1.9
#define OFFSET_ECFLG                   0x2E    // ECFLG Capture Interrupt Flag Register Section 15.3.4.1.10
#define OFFSET_ECCLR                   0x30    // ECCLR Capture Interrupt Clear Register Section 15.3.4.1.11
#define OFFSET_ECFRC                   0x32    // ECFRC Capture Interrupt Force Register Section 15.3.4.1.12
#define OFFSET_REVID                   0x5C    // REVID Revision ID Register Section 15.4.3.25

// eQEP related registers defines
#define eQEP0_BASE                     0x48300180  // PWMSS eQEP0 Registers
#define eQEP1_BASE                     0x48302180  // PWMSS eQEP1 Registers
#define eQEP2_BASE                     0x48304180  // PWMSS eQEP2 Registers

// Timer related registers
#define DMTIMER0_BASE                  0x44E05000  // DMTimer0 Registers
#define DMTIMER1_1MS_BASE              0x44E31000  // DMTimer1 1ms Registers
#define DMTIMER4_BASE                  0x48044000  // DMTimer4 Registers
#define DMTIMER5_BASE                  0x48046000  // DMTimer5 Registers
#define DMTIMER6_BASE                  0x48048000  // DMTimer6 Registers
#define DMTIMER7_BASE                  0x4804A000  // DMTimer7 Registers

#define OFFSET_TIDR                    0x00    // Identification Register
#define OFFSET_TIOCP_CFG               0x10    // Timer OCP Configuration Register
#define OFFSET_IRQ_EOI                 0x20    // Timer IRQ End-of-Interrupt Register
#define OFFSET_IRQSTATUS_RAW           0x24    // Timer Status Raw Register
#define OFFSET_IRQSTATUS               0x28    // Timer Status Register
#define OFFSET_IRQENABLE_SET           0x2C    // Timer Interrupt Enable Set Register
#define OFFSET_IRQENABLE_CLR           0x30    // Timer Interrupt Enable Clear Register
#define OFFSET_IRQWAKEEN               0x34    // Timer IRQ Wakeup Enable Register Section
#define OFFSET_TCLR                    0x38    // Timer Control Register Section
#define OFFSET_TCRR                    0x3C    // Timer Counter Register Section
#define OFFSET_TLDR                    0x40    // Timer Load Register
#define OFFSET_TTGR                    0x44    // Timer Trigger Register
#define OFFSET_TWPS                    0x48    // Timer Write Posting Bits Register
#define OFFSET_TMAR                    0x4C    // Timer Match Register
#define OFFSET_TCAR1                   0x50    // Timer Capture Register
#define OFFSET_TSICR                   0x54    // Timer Synchronous Interface Control Register
#define OFFSET_TCAR2                   0x58    // Timer Capture Register

#endif //_PRU_PWM_

PRUを実行管理するためのC言語プログラムは以下。
このプログラムはPRUプログラムをロードし実行し、100msec毎にPRUから割り込みをうけSHARED Memoryを介してキャプチャデータを取得してterminalに表示する。

/*
 * dmtimer.c
 */
#include &amp;amp;amp;amp;amp;lt;stdio.h&amp;amp;amp;amp;amp;gt;
#include &amp;amp;amp;amp;amp;lt;sys/mman.h&amp;amp;amp;amp;amp;gt;
#include &amp;amp;amp;amp;amp;lt;fcntl.h&amp;amp;amp;amp;amp;gt;
#include &amp;amp;amp;amp;amp;lt;errno.h&amp;amp;amp;amp;amp;gt;
#include &amp;amp;amp;amp;amp;lt;unistd.h&amp;amp;amp;amp;amp;gt;
#include &amp;amp;amp;amp;amp;lt;string.h&amp;amp;amp;amp;amp;gt;
#include &amp;amp;amp;amp;amp;lt;unistd.h&amp;amp;amp;amp;amp;gt;
#include &amp;amp;amp;amp;amp;lt;sched.h&amp;amp;amp;amp;amp;gt;

#include &quot;prussdrv.h&quot;
#include &amp;amp;amp;amp;amp;lt;pruss_intc_mapping.h&amp;amp;amp;amp;amp;gt;

#define PRU_NUM      0

#define OFFSET_MEM0      0x00000000
#define OFFSET_MEM1      0x00002000
#define OFFSET_SHAREDRAM 0x00010000

/******************************************************************************
* Global Variable Definitions                                                 *
******************************************************************************/

static void *pruDataMem;
//static unsigned int *pruDataMem_int0; /*AM33XX_DATA 8KB RAM0*/
//static unsigned int *pruDataMem_int1; /*AM33XX_DATA 8KB RAM1*/
static unsigned int *sharedMem_int;     /*AM33XX_SHARED 12KB RAM*/
//static unsigned int *currentBuffer_int;

/******************************************************************************
* Global Function Definitions                                                 *
******************************************************************************/

int main(int argc, char *argv[]) {
    unsigned int ret;
    struct sched_param sp;
    int policy;
    int result;
    tpruss_intc_initdata pruss_intc_initdata = PRUSS_INTC_INITDATA;

    /* change schduling policy to real-time */
    policy = SCHED_FIFO; /* we can select either SCHED_RR or SCHED_FIFO as policy. */
    sp.sched_priority = 1; /* we can select priority value within 1 to 99. */
    result = sched_setscheduler(0, policy, &amp;amp;amp;amp;amp;amp;sp);
    if (result) {
        printf(&quot;Unable to change schduling policy: sched_setscheduler = %d\n&quot;, result);
        return (0);
    }

    /* Initialize the PRU */
    prussdrv_init ();

    /* Open PRU Interrupt */
    ret = prussdrv_open(PRU_EVTOUT_0);
    if (ret) {
        printf(&quot;prussdrv_open open failed\n&quot;);
        return (0);
    }

    /* Get the interrupt initialized */
    prussdrv_pruintc_init(&amp;amp;amp;amp;amp;amp;pruss_intc_initdata);

    /* Execute example on PRU */
    printf(&quot;\tINFO: Executing example.\r\n&quot;);
    prussdrv_exec_program (PRU_NUM, &quot;./dmtimer.bin&quot;);
    prussdrv_map_prumem(PRUSS0_PRU0_DATARAM, &amp;amp;amp;amp;amp;amp;pruDataMem);
    sharedMem_int = (unsigned int*)(pruDataMem + OFFSET_SHAREDRAM );
    while (1) {
        /* Wait PRU0 interrupt event */
        prussdrv_pru_wait_event (PRU_EVTOUT_0);
        /* clear interrupt event */
        prussdrv_pru_clear_event (PRU_EVTOUT_0, PRU0_ARM_INTERRUPT);
        printf(&quot;[0] = %d, [1] = %d\n&quot;, sharedMem_int[0],sharedMem_int[1]);
        if (sharedMem_int[0] &amp;amp;amp;amp;amp;gt;= 2) break;
    }
    printf(&quot;pru is starting to capture.\n&quot;);

    /* main loop*/
    while (1) {
        /* Wait PRU0 interrupt event */
        prussdrv_pru_wait_event(PRU_EVTOUT_0);
        /* clear interrupt event */
        prussdrv_pru_clear_event(PRU_EVTOUT_0, PRU0_ARM_INTERRUPT);
        printf(&quot;i=%dHz,o=%dHz\n&quot;
            , sharedMem_int[1] * 10
            , sharedMem_int[1] * 10 / 4
        );
    }
    /* Wait PRU0 interrupt event */
    prussdrv_pru_wait_event(PRU_EVTOUT_0);
    /* clear interrupt event */
    prussdrv_pru_clear_event(PRU_EVTOUT_0, PRU0_ARM_INTERRUPT);

    /* Disable PRU and close memory mapping. */
    prussdrv_pru_disable(PRU_NUM);
    prussdrv_exit();
    return(0);
}

一応コンパイル済のソース一式を以下に格納しておく。
dmtimer_demo.tar.gz

ビルドは以下の手順で行う。

debian@beaglebone:~/pru/am335x_pru_package/pru_sw/dmtimer_demo$ export CROSS_COMPILE=
debian@beaglebone:~/pru/am335x_pru_package/pru_sw/dmtimer_demo$ make clean
debian@beaglebone:~/pru/am335x_pru_package/pru_sw/dmtimer_demo$ make
debian@beaglebone:~/pru/am335x_pru_package/pru_sw/dmtimer_demo$ cd bin/
debian@beaglebone:~/pru/am335x_pru_package/pru_sw/dmtimer_demo/bin$ cp ./dmtimer.bin ../dmtimer/obj/
debian@beaglebone:~/pru/am335x_pru_package/pru_sw/dmtimer_demo/bin$ cd ../dmtimer/obj/
debian@beaglebone:~/pru/am335x_pru_package/pru_sw/dmtimer_demo/dmtimer/obj$ gcc dmtimer.o -L../../../app_loader/lib -lprussdrv -lpthread -o dmtimer.out
debian@beaglebone:~/pru/am335x_pru_package/pru_sw/dmtimer_demo/dmtimer/obj$ 

このサンプルを実行するためにはTIMER4_OUT:P8_7とTIMER5_IN:P8_9を短絡する必要がある。
tclkinに適当な波形を与えるとその周波数を計測する。
今回は前述の24.576MHzオシレータ出力と、秋月で入手できる”1KHz~30MHzオシレータ LTC1799モジュール”を使う。
これらの測定信号をtclkinに入力し、TIMER5での周波数計測及びTIMER6/TIMER7のTimer出力に用いる。

回路図を以下に示す。

LTC1799モジュールはSETピンとVDDの間に設置したポテンショメータVR1の抵抗値により出力周波数を制御できるオシレータキット。
ジッタが大きいため精度を求める用途には向かないようだが、周波数レンジの広さと手軽さからとりあえずの用途に重宝する。
今回はVR1に多回転型半固定ボリューム50KΩを使う。
これも秋月で入手できる。
VR1を50KΩとした場合、V+が3.3Vの条件で約2MHz~20MHzの範囲の周波数を出力することができる。
もう少し低い周波数も欲しいのでVR1は100KΩとした方が良いが手持ちがなかった。
R1~R4はダンパ抵抗のつもりであるがちょっとテストするだけであるならば省略しても良いだろう。

今回この回路をブレッドボード上に組んだ。
SW1は実際にはジャンパを差し替えているだけで、tclkinへの入力信号を手動で切り替える。。

サンプルデモの実行は以下のように行う。
root権限が必要。
以下は24.576MHzオシレータをtclkinに入力した場合の結果。

debian@beaglebone:~/pru/am335x_pru_package/pru_sw/dmtimer_demo/dmtimer/obj$ sudo ./dmtimer.out
        INFO: Executing example.
[0] = 2, [1] = 0
pru is starting to capture.
i=12287560Hz,o=3071890Hz
i=24575380Hz,o=6143845Hz
i=24575410Hz,o=6143852Hz
i=24575390Hz,o=6143847Hz
i=24575420Hz,o=6143855Hz
i=24575410Hz,o=6143852Hz
i=24575410Hz,o=6143852Hz
i=24575390Hz,o=6143847Hz
i=24575380Hz,o=6143845Hz
i=24575390Hz,o=6143847Hz
i=24575390Hz,o=6143847Hz
i=24575400Hz,o=6143850Hz
i=24575390Hz,o=6143847Hz
i=24575390Hz,o=6143847Hz
i=24575390Hz,o=6143847Hz
i=24575390Hz,o=6143847Hz
i=24575380Hz,o=6143845Hz
i=24575380Hz,o=6143845Hz
i=24575380Hz,o=6143845Hz
i=24575390Hz,o=6143847Hz
i=24575390Hz,o=6143847Hz
i=24575390Hz,o=6143847Hz
i=24575390Hz,o=6143847Hz
i=24575400Hz,o=6143850Hz
i=24575380Hz,o=6143845Hz
i=24575390Hz,o=6143847Hz
i=24575380Hz,o=6143845Hz
i=24575380Hz,o=6143845Hz
i=24575390Hz,o=6143847Hz
i=24575390Hz,o=6143847Hz
i=24575390Hz,o=6143847Hz
i=24575390Hz,o=6143847Hz
i=24575390Hz,o=6143847Hz
i=24575380Hz,o=6143845Hz
i=24575390Hz,o=6143847Hz
i=24575390Hz,o=6143847Hz
i=24575400Hz,o=6143850Hz
i=24575390Hz,o=6143847Hz
i=24575400Hz,o=6143850Hz
i=24575390Hz,o=6143847Hz
i=24575380Hz,o=6143845Hz
i=24575400Hz,o=6143850Hz
i=24575390Hz,o=6143847Hz
i=24575400Hz,o=6143850Hz
i=24575390Hz,o=6143847Hz
i=24575400Hz,o=6143850Hz
i=24575390Hz,o=6143847Hz
i=24575400Hz,o=6143850Hz
i=24575390Hz,o=6143847Hz
i=24575400Hz,o=6143850Hz
i=24575390Hz,o=6143847Hz
i=24575390Hz,o=6143847Hz
i=24575390Hz,o=6143847Hz
i=24575390Hz,o=6143847Hz
i=24575390Hz,o=6143847Hz
i=24575380Hz,o=6143845Hz
i=24575390Hz,o=6143847Hz
i=24575390Hz,o=6143847Hz
i=24575370Hz,o=6143842Hz
i=24575360Hz,o=6143840Hz
i=24575380Hz,o=6143845Hz
i=24575390Hz,o=6143847Hz
i=24575390Hz,o=6143847Hz
i=24575400Hz,o=6143850Hz
i=24575390Hz,o=6143847Hz
i=24575400Hz,o=6143850Hz
i=24575400Hz,o=6143850Hz
i=24575390Hz,o=6143847Hz
i=24575400Hz,o=6143850Hz

ユーザーランドのCプログラムはPRUからのキャプチャ結果を受け表示し続ける。
止める場合はCtrl-Cで止める。
i はtclkinへの入力周波数を示し、o はTIMER6/TIMER7への出力周波数を示す。
i の1の位は桁合わせのためで常に0が表示される。
o は単に計算で出しているだけであるので出力周波数を保証するものではない。

測定誤差は測定に用いている基準クロックの誤差と1クロック分のジッタ、測定する信号の1クロック分のジッタが含まれる。
今回の方式では測定する信号の1クロック分のジッタ誤差は周波数が低くなってくると支配的になってくるので、tclkinに入力する信号の周波数が低い程測定精度は悪くなる。

初回はエラーが発生しているが概ねそこそこの精度で測定できている。

同様にLTC1799モジュールの出力信号をtclkinに入力してやるとVR1を調整することにより出力結果が変わることが確認できる。
LTC1799モジュールはジッタが大きいというネット上の情報があるが、自分の環境では言うほど悪いものではなく、AMの局発になら使えそうだ。
ただ、電源を入り切りするたびに大きく周波数がズレる。
これは恐らく温度特性のためであると思われるので、実際に使うためには通電後時間を置き温度を安定させる必要があるだろう。

今回、DMTimerを用いて周波数カウンタを実装できることを示せた。
周波数の測定を行いたいケースは多々あるので応用範囲が広いのではないだろうか。

タイトルとURLをコピーしました