PIN | OFFSET | PROC | NAME | MODE0 | MODE1 | MODE2 | MODE3 | MODE4 | MODE5 | MODE6 | MODE7 |
---|---|---|---|---|---|---|---|---|---|---|---|
P8.7 | 90h | R7 | TIMER4 | gpmc_advn_ale | timer4 | gpio2[2] | |||||
P8.8 | 94h | T7 | TIMER7 | gpmc_oen_ren | timer7 | gpio2[3] | |||||
P8.9 | 9Ch | T6 | TIMER5 | gpmc_be0n_cle | timer5 | gpio2[5] | |||||
P8.10 | 98h | U6 | TIMER6 | gpmc_wen | timer6 | gpio2[4] | |||||
P9.19 | 17Ch | D17 | I2C2_SCL | uart1_rtsn | timer5 | dcan0_rx | I2C2_SCL | spi1_cs1 | gpio0[13] | ||
P9.20 | 178h | D18 | I2C2_SDA | uart1_ctsn | timer6 | dcan0_tx | I2C2_SDA | spi1_cs0 | gpio0[12] | ||
P9.41 | 1B4h | D14 | CLKOUT2 | xdma_event_intr1 | tclkin | clkout2 | timer7_mux1 | EMU3_mux0 | gpio0[20] |
dtbファイルは次のようにした。
ポイントとしては、Mode設定に加えて、Inputに設定する必要がある。pullup/downは回路に合わせて設定すること。
/dts-v1/; /plugin/; / { compatible = "ti,beaglebone", "ti,beaglebone-black"; /* identification */ part-number = "BB-DMTIMER"; version = "00A0"; exclusive-use = "P8.07", "P8.08", "P8.09", "P8.10"; fragment@0 { target = <&am33xx_pinmux>; __overlay__ { timer_gpio: pinmux_timer_pins { pinctrl-single,pins = < 0x90 0x2a /* P8.07 timer5 IN|PUPD_OFF|MODE2 1 01 010 */ 0x94 0x2a /* P8.08 timer6 IN|PUPD_OFF|MODE2 1 01 010 */ 0x9C 0x2a /* P8.09 timer5 IN|PUPD_OFF|MODE2 1 01 010 */ 0x98 0x2a /* P8.10 timer6 IN|PUPD_OFF|MODE2 1 01 010 */ >; }; }; }; fragment@1 { target = <&ocp>; __overlay__ { test_helper: helper { compatible = "bone-pinmux-helper"; pinctrl-names = "default"; pinctrl-0 = <&timer_gpio>; status = "okay"; }; }; }; };
Offset 0x44E00000 + | Acronym |
---|---|
0h | CM_PER_L4LS_CLKSTCTRL |
4h | CM_PER_L3S_CLKSTCTRL |
Ch | CM_PER_L3_CLKSTCTRL |
14h | CM_PER_CPGMAC0_CLKCTRL |
18h | CM_PER_LCDC_CLKCTRL |
1Ch | CM_PER_USB0_CLKCTRL |
24h | CM_PER_TPTC0_CLKCTRL |
28h | CM_PER_EMIF_CLKCTRL |
2Ch | CM_PER_OCMCRAM_CLKCTRL |
30h | CM_PER_GPMC_CLKCTRL |
34h | CM_PER_MCASP0_CLKCTRL |
38h | CM_PER_UART5_CLKCTRL |
3Ch | CM_PER_MMC0_CLKCTRL |
40h | CM_PER_ELM_CLKCTRL |
44h | CM_PER_I2C2_CLKCTRL |
48h | CM_PER_I2C1_CLKCTRL |
4Ch | CM_PER_SPI0_CLKCTRL |
50h | CM_PER_SPI1_CLKCTRL |
60h | CM_PER_L4LS_CLKCTRL |
68h | CM_PER_MCASP1_CLKCTRL |
6Ch | CM_PER_UART1_CLKCTRL |
70h | CM_PER_UART2_CLKCTRL |
74h | CM_PER_UART3_CLKCTRL |
78h | CM_PER_UART4_CLKCTRL |
7Ch | CM_PER_TIMER7_CLKCTRL |
80h | CM_PER_TIMER2_CLKCTRL |
84h | CM_PER_TIMER3_CLKCTRL |
88h | CM_PER_TIMER4_CLKCTRL |
ACh | CM_PER_GPIO1_CLKCTRL |
B0h | CM_PER_GPIO2_CLKCTRL |
B4h | CM_PER_GPIO3_CLKCTRL |
BCh | CM_PER_TPCC_CLKCTRL |
C0h | CM_PER_DCAN0_CLKCTRL |
C4h | CM_PER_DCAN1_CLKCTRL |
CCh | CM_PER_EPWMSS1_CLKCTRL |
D4h | CM_PER_EPWMSS0_CLKCTRL |
D8h | CM_PER_EPWMSS2_CLKCTRL |
DCh | CM_PER_L3_INSTR_CLKCTRL |
E0h | CM_PER_L3_CLKCTRL |
E4h | CM_PER_IEEE5000_CLKCTRL |
E8h | CM_PER_PRU_ICSS_CLKCTRL |
ECh | CM_PER_TIMER5_CLKCTRL |
F0h | CM_PER_TIMER6_CLKCTRL |
F4h | CM_PER_MMC1_CLKCTRL |
F8h | CM_PER_MMC2_CLKCTRL |
FCh | CM_PER_TPTC1_CLKCTRL |
100h | CM_PER_TPTC2_CLKCTRL |
10Ch | CM_PER_SPINLOCK_CLKCTRL |
110h | CM_PER_MAILBOX0_CLKCTRL |
11Ch | CM_PER_L4HS_CLKSTCTRL |
120h | CM_PER_L4HS_CLKCTRL |
12Ch | CM_PER_OCPWP_L3_CLKSTCTRL |
130h | CM_PER_OCPWP_CLKCTRL |
140h | CM_PER_PRU_ICSS_CLKSTCTRL |
144h | CM_PER_CPSW_CLKSTCTRL |
148h | CM_PER_LCDC_CLKSTCTRL |
14Ch | CM_PER_CLKDIV32K_CLKCTRL |
150h | CM_PER_CLK_24MHZ_CLKSTCTRL |
CM_PER_TIMERx_CLKCTRL Register | ||||
---|---|---|---|---|
Bit | Field | Type | Reset | Description |
31-18 | Reserved | R | 0h | |
17-16 | IDLEST | R | 3h |
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 | R | 0h | |
1-0 | MODULEMODE | R/W | 0h |
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 transition cannot happen. 0x3 = RESERVED : Reserved |
Offset 0x44E00500 + | Acrynym | RegisterName |
---|---|---|
4h | CLKSEL_TIMER7_CLK | Selects the Mux select line for TIMER7 clock |
8h | CLKSEL_TIMER2_CLK | Selects the Mux select line for TIMER2 clock |
Ch | CLKSEL_TIMER3_CLK | Selects the Mux select line for TIMER3 clock |
10h | CLKSEL_TIMER4_CLK | Selects the Mux select line for TIMER4 clock |
14h | CM_MAC_CLKSEL | Selects the clock divide ration for MII clock |
18h | CLKSEL_TIMER5_CLK | Selects the Mux select line for TIMER5 clock |
1Ch | CLKSEL_TIMER6_CLK | Selects the Mux select line for TIMER6 clock |
20h | CM_CPTS_RFT_CLKSEL | Selects the Mux select line for CPTS RFT clock |
28h | CLKSEL_TIMER1MS_CLK | Selects the Mux select line for TIMER1 clock |
2Ch | CLKSEL_GFX_FCLK | Selects the divider value for GFX clock |
30h | CLKSEL_PRU_ICSS_OCP_CLK | Controls the Mux select line for PRU-ICSS OCP clock |
34h | CLKSEL_LCDC_PIXEL_CLK | Controls the Mux select line for LCDC PIXEL clock |
38h | CLKSEL_WDT1_CLK | Selects the Mux select line for Watchdog1 clock |
3Ch | CLKSEL_GPIO0_DBCLK | Selects the Mux select line for GPIO0 debounce clock |
CLKSEL_TIMERx_CLK Register Fiel Descriptions | ||||
---|---|---|---|---|
Bit | Field | Type | Reset | Description |
31-2 | Reserved | R | 0h | |
1-0 | CLKSEL | R/W | 1h |
Selects the Mux select line for TIMER2 clock 0x0 = SEL1 : Select TCLKIN clock 0x1 = SEL2 : Select CLK_M_OSC clock 0x2 = SEL3 : Select CLK_32KHZ clock 0x3 = SEL4 : Reserved |
Offset DMTIMER0 0x44E05000 DMTIMER1MS 0x44E31000 DMTIMER2 0x48040000 DMTIMER3 0x48042000 DMTIMER4 0x48044000 DMTIMER5 0x48046000 DMTIMER6 0x48048000 DMTIMER7 0x4804A000 | Acronym | Register Name |
---|---|---|
0h | TIDR | Identification Register |
10h | TIOCP_CFG | Timer OCP Configuration Register |
20h | IRQ_EOI | Timer IRQ End-of-Interrupt Register |
24h | IRQSTATUS_RAW | Timer Status Raw Register |
28h | IRQSTATUS | Timer Status Register |
2Ch | IRQENABLE_SET | Timer Interrupt Enable Set Register |
30h | IRQENABLE_CLR | Timer Interrupt Enable Clear Register |
34h | IRQWAKEEN | Timer IRQ Wakeup Enable Register |
38h | TCLR | Timer Control Register |
3Ch | TCRR | Timer Counter Register |
40h | TLDR | Timer Load Register |
44h | TTGR | Timer Trigger Register |
48h | TWPS | Timer Write Posting Bits Register |
4Ch | TMAR | Timer Match Register |
50h | TCAR1 | Timer Capture Register |
54h | TSICR | Timer Synchronous Interface Control Register |
58h | TCAR2 | Timer Capture Register |
Timer Control Register Field Descriptions | ||||
---|---|---|---|---|
Bit | Field | Type | Reset | Description |
31-15 | Reserved | R | 0h | |
14 | GPO_CFG | R/W | 0h |
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 | R/W | 0h |
Capture mode. 0h = Single capture 1h = Capture on second event |
12 | PT | R/W | 0h |
Pulse or toggle mode on PORTIMERPWM output pin 0h = Pulse 1h = Toggle |
11-10 | TRG | R/W | 0h |
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 | R/W | 0h |
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 | R/W | 0h |
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 | R/W | 0h |
0h = Compare mode is disabled 1h = Compare mode is enabled |
5 | PRE | R/W | 0h |
Prescaler enable 0h = The TIMER clock input pin clocks the counter 1h = The divided input pin clocks the counter |
4-2 | PTV | R/W | 0h | Pre-scale clock Timer value |
1 | AR | R/W | 0h |
0h = One shot timer 1h = Auto-reload timer |
0 | ST | R/W | 0h |
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 |
TCRRは基準クロックでカウントアップしてく読み書き可能なカウンタとなている。オーバーフローする際にイベントと、必要に応じ割込みを発生させることが出来る。
書き込みはいつでも直接行えるが、TLDRに初期値を設定しておき、オーバーフロー時や、TTGRに書き込みを行う事で初期値をロードさせることも可能となっている。
TMARは32bitのカウンタとなっていて、TCRRがTMARと同一の値となった場合に、イベントを発生させることが出来る。コンペアモードで使用される。
TCAR1, TCAR2はキャプチャモードでTCRRの値を保存するための32bitカウンタとなっている。
続いて代表的な設定例について見ていく。
簡単なライブラリを作ったので、レジスタのmmapとオフセット計算はライブラリに任せることにする。main関数のみ解説するので、詳細はソースを見てほしい。
TCRRがオーバーフローした際に、出力の極性を反転させることが出来るので、この機能を利用する。
パルス幅は1/2周期となるから、 基準クロックをFcとすると、 出力周波数Foは次式で表される。(ただし数値はuint32、Fc>Foとする)
Fo = Fc/2(-TCRR)
TCRR=-Fc/2Fo
TCRRへの初期値のロードはオーバーフローした際にTLDRの値を自動的にロードする機能を使用する。
この場合の設定は次のようになる。
TLDR=前述の式から導かれる値
TCRR=同上
TCLRレジスタは次のような設定となる。
プリスケーラーを使用する必要がある場合は、PRE, PTVも適切に設定します。
#include <stdint.h> #include <stdio.h> #include <bbb_dmtimer.h> int main(void){ // initialize DMTIMER lib if(bbb_dmtimer_init()){ fprintf(stderr, "Can not initialize bbb_dmtimer lib\n"); return(1); } /* * DMTIMER6 configuration * 1MHz, 50% duty cycle */ // Timer6 enable CM_PER[CM_PER_TIMER6_CLKCTRL] = MODULE_ENABLED; // Set 0x44E000F0 to 0x02 // Set TCRR clock source CM_DPLL[CLKSEL_TIMER6_CLK] = CLK_M_OSC; // Set 0x44E0051C to 0x1 // Set TLDR value(1/2 wave length) DMTIMER[6][TLDR] = (uint32_t)(-12); // Set 0x48048040 to 0xFFFFFFF4 // Set initial TCRR value DMTIMER[6][TCRR] = DMTIMER[6][TLDR]; // Set 0x4804803C to 0xFFFFFFF4 // Set free run cuonter // GPO_CFG[14] = 0(Output) // CAPT_MODE[13] = X(Don't care) // PT[12] = 1(Toggle) // TRG[11-10] = 1(Trigger on overflow) // TCM[9-8] = X(Don't care) // SCPWM[7] = X(Don't care) // CE[6] = 0(Compare mode is disabled) // PRE[5] = 0(Prescaler disable) // PTV[4-2] = X(Don't care) // AR[1] = 1(Auto-reload timer) // ST[0] = 1(Start timer) DMTIMER[6][TCLR] = 0x1403; // Set 0x48048038 to 0x1403 bbb_dmtimer_free(); return(0); }
前述の任意周波数出力の設定に加えてCompare Modeを利用し、TCRR==TMARとなった際にもイベントを発生させて極性を反転させる。
TCRR~0xffffffffの間の任意の値にTMARを設定する。
TCLRレジスタは次のような設定となる。
ドキュメントのSCPWMの説明がわかりにくいが、1に設定すると極性が反転するので、都合の良い方を選択すればよい。
#include <stdint.h> #include <stdio.h> #include <bbb_dmtimer.h> int main(void){ // initialize DMTIMER lib if(bbb_dmtimer_init()){ fprintf(stderr, "Can not initialize bbb_dmtimer lib\n"); return(1); } /* * DMTIMER5 configuration * 1KHz, 25% duty cycle */ // Timer5 enable CM_PER[CM_PER_TIMER5_CLKCTRL] = MODULE_ENABLED; // Set 0x44E000EC to 0x02 // Set TCRR clock source CM_DPLL[CLKSEL_TIMER5_CLK] = CLK_M_OSC; // Set 0x44E00518 to 0x1 // Set TLDR value(wave length) DMTIMER[5][TLDR] = (uint32_t)(-24000); // Set 0x48046040 to 0xFFFFFFA240 // Set initial TCRR value DMTIMER[5][TCRR] = DMTIMER[5][TLDR]; // Set 0x4804603C to 0xFAAAAAAB // Set match value of falling edge DMTIMER[5][TMAR] = (uint32_t)(-18000); // Set 0x4804604C to 0xFFFFFF6960 // Set PWM // GPO_CFG[14] = 0(Output) // CAPT_MODE[13] = X(Don't care) // PT[12] = 1(Toggle) // TRG[11-10] = 2(Trigger on overflow and match) // TCM[9-8] = X(Don't care) // SCPWM[7] = 0 // CE[6] = 1(Compare mode is enableed) // PRE[5] = 0(Prescaler disable) // PTV[4-2] = X(Don't care) // AR[1] = 1(Auto-reload timer) // ST[0] = 1(Start timer) DMTIMER[5][TCLR] = 0x1843; // Set 0x48046038 to 0x18C3 bbb_dmtimer_free(); return(0); }
タイマーI/Oを入力に設定し、Capture modeを使用して入力信号でTCRRの値をキャプチャさせる。
2回キャプチャして、それぞれの値をTCAR1, TCAR2に保存する機能があるので、これを利用する。
キャプチャが完了すると、割り込みを発生し、キャプチャは停止するので、測定値を読み込んだ後、プログラムで割込みフラグをリセットし次の測定を開始させる。
TCRRがオーバーフローした際は0に戻ってほしいので、TLDR=0, AR=1とする必要がある。TCRRの初期値は何でも構わないので初期化は不要である。
TCLRレジスタは次のような設定となる。
割込みはIRQENABLE_SETレジスタで有効に設定し、発生はIRQSTATUSで読み取れる。クリアはIRQSTATUSの該当フラグに1を書き込むことにより行う。0を書き込むわけではないので注意。
割込みと言っても、OS上のプログラムに割込みがかかるわけではないので、発生はIRQSTATUSレジスタをポーリングする事で確認する。
IRQSTATUSにTCAR_EN_FLAGがセットされていれば、キャプチャが完了しているから、TCAR2-TCAR2 Clockが周期となる。
この方法は比較的測定周期が長い場合に適当である。周波数が高くなると分解能が下がるので、数百khz程度までが実用範囲だろう。より高い周波数を測定したい場合は、tclkinに測定対象の信号を入力してTCRRを回しておき、別のタイマ信号でキャプチャを行わせればよいだろう。
#include <stdint.h> #include <stdio.h> #include <bbb_dmtimer.h> int main(void){ // initialize DMTIMER lib if(bbb_dmtimer_init()){ fprintf(stderr, "Can not initialize bbb_dmtimer lib\n"); return(1); } // Timer6 enable CM_PER[CM_PER_TIMER6_CLKCTRL] = MODULE_ENABLED; // Set 0x44E000F0 to 0x02 // Set TCRR clock source CM_DPLL[CLKSEL_TIMER6_CLK] = CLK_M_OSC; // Set 0x44E0051C to 0x1 // Set TLDR value DMTIMER[6][TLDR] = 0; // Set 0x48048040 to 0x0 // Omit TCRR initialization because any value is OK. // Set interrupt DMTIMER[6][IRQENABLE_SET] |= TCAR_EN_FLAG; // Set 0x48048040 to 0x4 // Clear interrupt flag DMTIMER[6][IRQSTATUS] |= TCAR_EN_FLAG; // Set 0x48048040 to 0x4 // Set free run cuonter // GPO_CFG[14] = 1(Input) // CAPT_MODE[13] = 1(Capture on second event) // PT[12] = X(Don't care) // TRG[11-10] = 00(No trigger) // TCM[9-8] = 01(Capture on low to high transition) // SCPWM[7] = X(Don't care) // CE[6] = 0(Compare mode is disabled) // PRE[5] = 0(Prescaler disable) // PTV[4-2] = X(Don't care) // AR[1] = 1(Auto-reload timer) // ST[0] = 1(Start timer) DMTIMER[6][TCLR] = 0x6103; // Set 0x48048038 to 0x6103 while(1){ if(DMTIMER[6][IRQSTATUS]){ uint32_t cycle = DMTIMER[6][TCAR2] - DMTIMER[6][TCAR1]; printf("%.2f Hz\n", (float)24000000/cycle); // Clear interrupt flag DMTIMER[6][IRQSTATUS] |= TCAR_EN_FLAG; } } // not reach bbb_dmtimer_free(); return(0); }
Debianではdevmem2が無くなっていしまったようだが、busyboxコマンドが同様の機能を持っているので、これを使ってシェルからレジスタの変更や状態の確認が行える。
使用例
#!/bin/sh # # shell script example # # Mux is set to timer, universal cape draiver is required config-pin p9.19 timer config-pin p9.20 timer # CM_PER_TIMER6_CLKCTRL busybox devmem 0x44E000F0 32 0x02 # CLKSEL_TIMER6_CLK busybox devmem 0x44E0051C 32 0x1 # DMTIMER6 TLDR busybox devmem 0x48048040 32 0xFFFFFFF4 # DMTIMER6 TCRR busybox devmem 0x4804803C 32 0xFFFFFFF4 # DMTIMER6 TLCR busybox devmem 0x48048038 32 0x1403 busybox devmem 0x44E000F0 32 busybox devmem 0x44E0051C 32 busybox devmem 0x48048040 32 busybox devmem 0x4804803C 32 busybox devmem 0x48048038 32