BBBのPWMSSモジュールの使い方

概要

BeagleBone Blackに搭載されているAM335xのPWMSS(Pulse-Width Modulation Subsystem)を使用する方法について説明する。
kernel 4.19.94-ti-r42を前提とする。
AM335xには、3個のPWMSSが搭載されている。PWMSSはモードによって以下の機能を提供する。クロックは100MHzとなっており、DMTimerよりも高速な処理が必要な場合に用いることが出来る。

それぞれの機能で入出力ピンが異なっており、それらがマルチプレクサを介してヘッダーに出ている為、機能ごとに分けて説明する。
機会があれば追々調べて行こうと思うが、差し当たり当方で使いたかったeCAP機能について調べた結果を以下に示す。
詳細についてはTexas Instruments提供のAM335x and AMIC110 Sitara Processors Technical Reference Manualを参照の事。

設定方法

ubootの設定

BBBの場合、ピンヘッダに入出力ピンが出ており、dtbの設定で割り当てを何通りか変更できるため、どのピンを使用するかを予め検討しておく必要がある。
dtbファイルで必要な入出力ピンを有効にしておく。あるいは、一時的にであれば、universal capeをenableにしておき、config-pinコマンドでtimerに割り当てる事でも設定可能(だとおもう)。
以下に、関連するMux設定の抜粋を示す。詳細はBBBのリッファレンスマニュアルを参照の事。

eHPWM

PINOFFSET
44e10800+
PROCNAMEMODE0MODE1MODE2MODE3MODE4MODE5MODE6MODE7
P8.1324hT10EHRPWM2Bgpmc_ad9lcd_data22mmc1_dat1mmc2_dat5ehrpwm2Bgpio0[23]
P8.1428hT11GPIO0_26gpmc_ad10lcd_data21mmc1_dat2mmc2_dat6ehrpwm2_tripzone_ingpio0[26]
P8.172chU12GPIO0_27gpmc_ad11lcd_data20mmc1_dat3mmc2_dat7ehrpwm0_syncogpio0[27]
P8.1920hU10EHRPWM2Agpmc_ad8lcd_data23mmc1_dat0mmc2_dat4ehrpwm2Agpio0[22]
P8.34cchU4UART3_RTSNlcd_data11gpmc_a15ehrpwm1Bmcasp0_ahclkrmcasp0_axr2uart3_rtsngpio2[17]
P8.36c8hU3UART3_CTSNlcd_data10gpmc_a14ehrpwm1Amcasp0_axr0uart3_ctsngpio2[16]
P8.37c0hU1UART5_TXDlcd_data8gpmc_a12ehrpwm1_tripzone_inmcasp0_aclkxuart5_txduart2_ctsngpio2[14]
P8.38c4hU2UART5_RXDlcd_data9gpmc_a13ehrpwm0_syncomcasp0_fsxuart5_rxduart2_rtsngpio2[15]
P8.43a8hR3GPIO2_8lcd_data2gpmc_a2ehrpwm2_tripzone_ingpio2[8]
P8.44achR4GPIO2_9lcd_data3gpmc_a3ehrpwm0_syncogpio2[9]
P8.45a0hR1GPIO2_6lcd_data0gpmc_a0ehrpwm2Agpio2[6]
P8.46a4hR2GPIO2_7lcd_data1gpmc_a1ehrpwm2Bgpio2[7]
P9.1448hU14EHRPWM1Agpmc_a2mii2_txd3rgmii2_td3mmc2_dat1gpmc_a18ehrpwm1A_mux1gpio1[18]
P9.1540hR13GPIO1_16gpmc_a0gmii2_txenrmii2_tctlmii2_txengpmc_a16ehrpwm1_tripzone_inputgpio1[16]
P9.164chT14EHRPWM1Bgpmc_a3mii2_txd2rgmii2_td2mmc2_dat2gpmc_a19ehrpwm1B_mux1gpio1[19]
P9.1715chA16I2C1_SCLspi0_cs0mmc2_sdwpI2C1_SCLehrpwm0_syncigpio0[5]
P9.18158hB16I2C1_SDAspi0_d1mmc1_sdwpI2C1_SDAehrpwm0_tripzonegpio0[4]
P9.21154hB17UART2_TXDspi0_d0uart2_txdI2C2_SCLehrpwm0BEMU3_mux1gpio0[3]
P9.22150hA17UART2_RXDspi0_sclkuart2_rxdI2C2_SDAehrpwm0AEMU2_mux1gpio0[2]
P9.2344hV14GPIO1_17gpmc_a1gmii2_rxdvrgmii2_rxdvmmc2_dat0gpmc_a17ehrpwm0_syncogpio1[17]
P9.42A164hC18GPIO0_7eCAP0_in_PWM0_outuart3_txdspi1_cs1pr1_ecap0_ecap_capin_apwm_ospi1_sclkmmc0_sdwpxdma_event_intr2gpio0[7]
P9.42B1a0hB12GPIO3_18Mcasp0_aclkreQEP0A_inMcaspo_axr2Mcasp1_aclkxgpio3[18]

P9.42は2つのGPIOで共有されているので、使用しない方はハイインピーダンス状態としておく必要がある。

eCAP

PINOFFSET
44e10800+
PROCNAMEMODE0MODE1MODE2MODE3MODE4MODE5MODE6MODE7
P9.2819chC12 SPI1_CS0 mcasp0_ahclkr ehrpwm0_synci mcasp0_axr2 spi1_cs0 eCAP2_in_PWM2_out pr1_pru0_pru_r30_3 pr1_pru0_pru_r31_3 gpio3[17]
P9.42A164hC18GPIO0_7eCAP0_in_PWM0_outuart3_txdspi1_cs1pr1_ecap0_ecap_capin_apwm_ospi1_sclkmmc0_sdwpxdma_event_intr2gpio0[7]
P9.42B1a0hB12GPIO3_18Mcasp0_aclkreQEP0A_inMcaspo_axr2Mcasp1_aclkxgpio3[18]

P9.28はデフォルトでHDMIの音声出力に割り当てられているのでHDMIをdisableにしておく必要がある。
P9.42は2つのGPIOで共有されているので、使用しない方はハイインピーダンス状態としておく必要がある。

eCAP1は内部でJ1のUART0_TXに接続されており、cape managerでこのピンは設定を変更する機能が提供されていない為使用できない。従って、BBBで利用できるのはeCAP0とeCAP2の2つとなる。

以下のdtsファイルを作成した。

/dts-v1/;
/plugin/;
  
/ {
    compatible = "ti,beaglebone", "ti,beaglebone-black";
  
    /* identification */
    part-number = "BB-eCAP";
    version = "00A0";
  
    exclusive-use =
        "P9.42",
        "P9.28",
        "eCAP0_in_PWM0_out",
        "eCAP2_in_PWM2_out";

    fragment@0 {
        target = <&am33xx_pinmux>;
        __overlay__ {
            ecap0_gpio: pinmux_ecap0_pins {
                pinctrl-single,pins = <
                    0x164 0x28  /* (IN|PU_DIS|MODE0)=(0 01 000) eCAP0_in_PWM0_out P9.42 */
                >;
            };
            ecap2_gpio: pinmux_ecap2_pins {
                pinctrl-single,pins = <
                    0x19C 0x2c  /* (IN|PU_DIS|MODE4)=(0 01 100) eCAP2_in_PWM2_out_mux1 P9.28 */
                >;
            };
            gpio3_gpio: pinmux_gpio3_pins {
                pinctrl-single,pins = <
                    0x1A0 0x2f  /* (IN|PU_DIS|MODE7)=(1 01 111) gpio3[18], set Hi-Z P9.42 */
                >;
            };
        };
    };

  
    fragment@1 {
        target = <&ocp>;
        __overlay__ {
            bb_ecap0 {
                compatible      = "bb-ecap";
                pwms            = <&ecap0 0 0 1>;
                pwm-names       = "ECAP0";
                pinctrl-names   = "default";
                pinctrl-0       = <&ecap0_gpio>;
                enabled         = <1>;
                duty            = <0>;
                status          = "okay";
            };
            bb_ecap2 {
                compatible      = "bb-ecap";
                pwms            = <&ecap2 0 0 1>;
                pwm-names       = "ECAP2";
                pinctrl-names   = "default";
                pinctrl-0       = <&ecap2_gpio>;
                enabled         = <1>;
                duty            = <0>;
                status          = "okay";
            };
            bb_ecap0_gpio_helper: ecap0_gpio_helper {
                compatible      = "bone-pinmux-helper";
                pinctrl-names   = "default";
                pinctrl-0       = <&ecap0_gpio>;
                status          = "okay";
            };
            bb_ecap2_gpio_helper: ecap2_gpio_helper {
                compatible      = "bone-pinmux-helper";
                pinctrl-names   = "default";
                pinctrl-0       = <&ecap2_gpio>;
                status          = "okay";
            };
            bb_gpio3_gpio_helper: gpio3_gpio_helper {
                compatible      = "bone-pinmux-helper";
                pinctrl-names   = "default";
                pinctrl-0       = <&gpio3_gpio>;
                status          = "okay";
            };
        };
    };
  
    fragment@2 {
        target = <&pruss>;
        __overlay__ {
            status          = "okay";
        };
    };
};

一時的にであれば、config-pinコマンドで次のように設定すればよい模様。
PRUから操作する場合はpru_ecapにする必要があるかも。
GPIO3_18については、この場合どういう設定になるのかよくわからないが、GPIOはデフォルトでinputになっているので、特に弄っていなければ、問題はないだろう。
P9.28には、pwmとpwm2という選択肢があるが、pwm2にしないと動作しなかった。どういった違いがあるのかは調べていない。

root@beaglebone:/sys/class/pwm/pwm-6:0# config-pin -l P9.28

Available modes for P9_28 are: default gpio gpio_pu gpio_pd gpio_input spi_cs pwm pwm2 pruout pruin

root@beaglebone:/sys/class/gpio/gpio7# config-pin P9.28 pwm2

Current mode for P9_28 is:     pwm2

root@beaglebone:/sys/class/pwm/pwm-6:0# config-pin -l P9.42

Available modes for P9_42 are: default gpio gpio_pu gpio_pd gpio_input spi_cs spi_sclk uart pwm pru_ecap

root@beaglebone:/sys/class/gpio/gpio7# config-pin P9.42 pwm

Current mode for P9_42 is:     pwm
PWM output

さしあたり、この設定でPWMの出力が出来るかテストする。
eCAP0, eCAP2がどのデバイスツリーに紐づけられているのか、kernel versionによって異なっていたりして明確な資料が見つからないが、 実機を調べると、メモリアドレスとリンク先のデバイス名が一致している模様。
つまり、pwm-0:0がeCAP0、pwm-6:0がeCAP2ということのようだ。
周期はnsec指定、duty cycleは1/10000%で指定する。

この結果右図のような出力が得られた。eCAP0とeCAP2の開始時期は同期していないので毎回ズレるが、レジスタで同期機能を設定すれば同期させることもできるだろう。

root@beaglebone:/sys/class/pwm# ls -l
total 0
lrwxrwxrwx 1 root root 0 Jan 17 13:31 pwm-0:0 -> ../../devices/platform/ocp/48300000.epwmss/48300100.ecap/pwm/pwmchip0/pwm-0:0
lrwxrwxrwx 1 root root 0 Jan 17 13:31 pwm-1:0 -> ../../devices/platform/ocp/48300000.epwmss/48300200.pwm/pwm/pwmchip1/pwm-1:0
lrwxrwxrwx 1 root root 0 Jan 17 13:31 pwm-1:1 -> ../../devices/platform/ocp/48300000.epwmss/48300200.pwm/pwm/pwmchip1/pwm-1:1
lrwxrwxrwx 1 root root 0 Jan 17 13:31 pwm-3:0 -> ../../devices/platform/ocp/48302000.epwmss/48302100.ecap/pwm/pwmchip3/pwm-3:0
lrwxrwxrwx 1 root root 0 Jan 17 13:31 pwm-4:0 -> ../../devices/platform/ocp/48302000.epwmss/48302200.pwm/pwm/pwmchip4/pwm-4:0
lrwxrwxrwx 1 root root 0 Jan 17 13:31 pwm-4:1 -> ../../devices/platform/ocp/48302000.epwmss/48302200.pwm/pwm/pwmchip4/pwm-4:1
lrwxrwxrwx 1 root root 0 Jan 17 13:31 pwm-6:0 -> ../../devices/platform/ocp/48304000.epwmss/48304100.ecap/pwm/pwmchip6/pwm-6:0
lrwxrwxrwx 1 root root 0 Jan 17 13:31 pwm-7:0 -> ../../devices/platform/ocp/48304000.epwmss/48304200.pwm/pwm/pwmchip7/pwm-7:0
lrwxrwxrwx 1 root root 0 Jan 17 13:31 pwm-7:1 -> ../../devices/platform/ocp/48304000.epwmss/48304200.pwm/pwm/pwmchip7/pwm-7:1
lrwxrwxrwx 1 root root 0 Jan 17 13:31 pwmchip0 -> ../../devices/platform/ocp/48300000.epwmss/48300100.ecap/pwm/pwmchip0
lrwxrwxrwx 1 root root 0 Jan 17 13:31 pwmchip1 -> ../../devices/platform/ocp/48300000.epwmss/48300200.pwm/pwm/pwmchip1
lrwxrwxrwx 1 root root 0 Jan 17 13:31 pwmchip3 -> ../../devices/platform/ocp/48302000.epwmss/48302100.ecap/pwm/pwmchip3
lrwxrwxrwx 1 root root 0 Jan 17 13:31 pwmchip4 -> ../../devices/platform/ocp/48302000.epwmss/48302200.pwm/pwm/pwmchip4
lrwxrwxrwx 1 root root 0 Jan 17 13:31 pwmchip6 -> ../../devices/platform/ocp/48304000.epwmss/48304100.ecap/pwm/pwmchip6
lrwxrwxrwx 1 root root 0 Jan 17 13:31 pwmchip7 -> ../../devices/platform/ocp/48304000.epwmss/48304200.pwm/pwm/pwmchip7

root@beaglebone:/sys/class/pwm/pwm-0:0# ls
capture  device  duty_cycle  enable  period  polarity  power  subsystem  uevent
root@beaglebone:/sys/class/pwm/pwm-0:0# echo 1000000 > period
root@beaglebone:/sys/class/pwm/pwm-0:0# echo 1 > enable
root@beaglebone:/sys/class/pwm/pwm-0:0# echo 25000 > duty_cycle
root@beaglebone:/sys/class/pwm/prm-0:0# cd ../pwm-6\:0
root@beaglebone:/sys/class/pwm/pwm-6:0# echo 1000000 > period
root@beaglebone:/sys/class/pwm/pwm-6:0# echo 500000 > duty_cycle
root@beaglebone:/sys/class/pwm/pwm-6:0# echo 1 > enable

eQEP

PINOFFSETPROCNAMEMODE0MODE1MODE2MODE3MODE4MODE5MODE6MODE7
P8.11hR12GPIO1_13gpmc_ad13lcd_data18mmc1_dat5mmc2_dat1eQEP2B_ingpio1[13]
P8.12hT12GPIO1_12GPMC_AD12LCD_DATA19Mmc1_dat4MMC2_DAT0EQEP2A_INgpio1[12]
P8.15hU13GPIO1_15gpmc_ad15lcd_data16mmc1_dat7mmc2_dat3eQEP2_strobegpio1[15]
P8.16hV13GPIO1_14gpmc_ad14lcd_data17mmc1_dat6mmc2_dat2eQEP2_indexgpio1[14]
P8.31hV4UART5_CTSNlcd_data14gpmc_a18eQEP1_indexmcasp0_axr1uart5_rxduart5_ctsngpio0[10]
P8.32hT5UART5_RTSNlcd_data15gpmc_a19eQEP1_strobemcasp0_ahclkxmcasp0_axr3uart5_rtsngpio0[11]
P8.33hV3UART4_RTSNlcd_data13gpmc_a17eQEP1B_inmcasp0_fsrmcasp0_axr3uart4_rtsngpio0[9]
P8.35hV2UART4_CTSNlcd_data12gpmc_a16eQEP1A_inmcasp0_aclkrmcasp0_axr2uart4_ctsngpio0[8]
P8.39hT3GPIO2_12lcd_data6gpmc_a6eQEP2_indexgpio2[12]
P8.40hT4GPIO2_13lcd_data7gpmc_a7eQEP2_strobepr1_edio_data_out7gpio2[13]
P8.41hT1GPIO2_10lcd_data4gpmc_a4eQEP2A_ingpio2[10]
P8.42hT2GPIO2_11lcd_data5gpmc_a5eQEP2B_ingpio2[11]
P9.25hA14GPIO3_21mcasp0_ahclkxeQEP0_strobemcasp0_axr3mcasp1_axr1EMU4_mux2gpio3[21]
P9.27hC13GPIO3_19mcasp0_fsreQEP0B_inmcasp0_axr3mcasp1_fsxEMU2_mux2gpio3[19]
P9.41AhD14CLKOUT2xdma_event_intr1tclkinclkout2timer7_mux1EMU3_mux0gpio0[20]
P9.41BhD13GPIO3_20mcasp0_axr1eQEP0_indexMcasp1_axr0emu3gpio3[20]
P9.42AhC18GPIO0_7eCAP0_in_PWM0_outuart3_txdspi1_cs1pr1_ecap0_ecap_capin_apwm_ospi1_sclkmmc0_sdwpxdma_event_intr2gpio0[7]
P9.42BhB12GPIO3_18Mcasp0_aclkreQEP0A_inMcaspo_axr2Mcasp1_aclkxgpio3[18]

P9.41, P9.42は2つのGPIOで共有されているので、使用しない方はハイインピーダンス状態としておく必要がある。

PWMSS moduleのenable

PWMSS moduleはデフォルトでdisableになっているので、CM_PER registerのCM_PER_EPWMSSx_CLKCTRLレジスタで有効に設定する必要がある。
この設定を行わないと、PWMSS関連レジスタへのアクセスもBus errorになる。

Offset
0x44E00000 +
Acronym
0hCM_PER_L4LS_CLKSTCTRL
4hCM_PER_L3S_CLKSTCTRL
ChCM_PER_L3_CLKSTCTRL
14hCM_PER_CPGMAC0_CLKCTRL
18hCM_PER_LCDC_CLKCTRL
1ChCM_PER_USB0_CLKCTRL
24hCM_PER_TPTC0_CLKCTRL
28hCM_PER_EMIF_CLKCTRL
2ChCM_PER_OCMCRAM_CLKCTRL
30hCM_PER_GPMC_CLKCTRL
34hCM_PER_MCASP0_CLKCTRL
38hCM_PER_UART5_CLKCTRL
3ChCM_PER_MMC0_CLKCTRL
40hCM_PER_ELM_CLKCTRL
44hCM_PER_I2C2_CLKCTRL
48hCM_PER_I2C1_CLKCTRL
4ChCM_PER_SPI0_CLKCTRL
50hCM_PER_SPI1_CLKCTRL
60hCM_PER_L4LS_CLKCTRL
68hCM_PER_MCASP1_CLKCTRL
6ChCM_PER_UART1_CLKCTRL
70hCM_PER_UART2_CLKCTRL
74hCM_PER_UART3_CLKCTRL
78hCM_PER_UART4_CLKCTRL
7ChCM_PER_TIMER7_CLKCTRL
80hCM_PER_TIMER2_CLKCTRL
84hCM_PER_TIMER3_CLKCTRL
88hCM_PER_TIMER4_CLKCTRL
AChCM_PER_GPIO1_CLKCTRL
B0hCM_PER_GPIO2_CLKCTRL
B4hCM_PER_GPIO3_CLKCTRL
BChCM_PER_TPCC_CLKCTRL
C0hCM_PER_DCAN0_CLKCTRL
C4hCM_PER_DCAN1_CLKCTRL
CChCM_PER_EPWMSS1_CLKCTRL
D4hCM_PER_EPWMSS0_CLKCTRL
D8hCM_PER_EPWMSS2_CLKCTRL
DChCM_PER_L3_INSTR_CLKCTRL
E0hCM_PER_L3_CLKCTRL
E4hCM_PER_IEEE5000_CLKCTRL
E8hCM_PER_PRU_ICSS_CLKCTRL
EChCM_PER_TIMER5_CLKCTRL
F0hCM_PER_TIMER6_CLKCTRL
F4hCM_PER_MMC1_CLKCTRL
F8hCM_PER_MMC2_CLKCTRL
FChCM_PER_TPTC1_CLKCTRL
100hCM_PER_TPTC2_CLKCTRL
10ChCM_PER_SPINLOCK_CLKCTRL
110hCM_PER_MAILBOX0_CLKCTRL
11ChCM_PER_L4HS_CLKSTCTRL
120hCM_PER_L4HS_CLKCTRL
12ChCM_PER_OCPWP_L3_CLKSTCTRL
130hCM_PER_OCPWP_CLKCTRL
140hCM_PER_PRU_ICSS_CLKSTCTRL
144hCM_PER_CPSW_CLKSTCTRL
148hCM_PER_LCDC_CLKSTCTRL
14ChCM_PER_CLKDIV32K_CLKCTRL
150hCM_PER_CLK_24MHZ_CLKSTCTRL
CM_PER_PWMSSx_CLKCTRL Register
BitFieldTypeResetDescription
31-18ReservedR0h
17-16IDLESTR3h 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-2ReservedR0h
1-0MODULEMODER/W0h 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 from:
0x4830_0000
0x4830_2000
0x4830_4000
Acronym
0hIDVER Register
4hSYSCONFIG Register
8hCLKCONFIG Register
chCLKSTATUS Register

eCAP Functionの動作

さらに、CaptureモードとAPWMモードがある。
入出力はモードによって決まる。

Capture modeでは入力信号はプリスケーラーで分周した後、立ち上がり、立下りの何れか、若しくは双方を対象にTSCTRレジスタの値がCAP1-CAP4まで順次保存される。
TSCTRレジスタはクロック若しくは同期信号によるフリーランカウンタで、オーバーフロー時はCTR_OVFがセットされる。
計測が完了した際、割込みを発生させることが出来る。CAPxレジスタの時刻を比較する事で、周期若しくは周波数を計算できる。

eCAP Registers
Offset from:
0x4830_0100
0x4830_2100
0x4830_4100
Acronym
0hTSCTR Time-Stamp Counter Register
4hCTRPHS Counter Phase Offset Value Register
8hCAP1 Capture 1 Register
ChCAP2 Capture 2 Register
10hCAP3 Capture 3 Register
14hCAP4 Capture 4 Register
28hECCTL1 Capture Control Register 1
2AhECCTL2 Capture Control Register 2
2ChECEINT Capture Interrupt Enable Register
2EhECFLG Capture Interrupt Flag Register
30hECCLR Capture Interrupt Clear Register
32hECFRC Capture Interrupt Force Register
5ChREVID Revision ID Register
TSCTR
BitFieldTypeResetDescription
31-0TSCTRR/W0hActive 32bit counter register that is used as the capture time-base
CTRPHS
BitFieldTypeResetDescription
31-0CTRPHSR/W0hCounter phase value register that can be programmed for phase lag/lead.
This register shadows TSCTR and is loaded into TSCTR upon either a SYNCI event or S/W force via a control bit. Used to achieve phase control synchronization with respect to other eCAP and EPWM time-base
CAPx
BitFieldTypeResetDescription
31-0CAPxR/W0h This register can be loaded (written) by the following.
(a) Time-Stamp (that is, counter value) during a capture event.
(b) Software may be useful for test purposes.
(c) APRD active register when used in APWM mode
ECCTL1
BitFieldTypeResetDescription
15-14FREE_SOFTR/W0hEmulation Control
0h=TSCTR counter stops immediately on emulation suspend.
1h=TSCTR counter runs until 0.
2h & 3h=TSCTR counter is unaffected by emulation suspend(Run Free).
13-9PRESCALER/W0hEvent Filter prescale slect
分周比=2*N, 0の場合Disable
8CAPLDENR/W0hEnable Loading of CAP1 to CAP4 registers on a capture event
0h=Disable
1h=Enable
7CTRRST4R/W0hCounter Reset on Capture Event 4
0h=Disable
1h=Enable
6CAP4POLR/W0hCapture Event 4 Polarity select
0h=Rising edge
1h=Falling edge
5CTRRST3R/W0hCounter Reset on Capture Event 3
0h=Disable
1h=Enable
4CAP3POLR/W0hCapture Event 3 Polarity select
0h=Rising edge
1h=Falling edge
3CTRRST2R/W0hCounter Reset on Capture Event 2
0h=Disable
1h=Enable
2CAP2POLR/W0hCapture Event 2 Polarity select
0h=Rising edge
1h=Falling edge
1CTRRST1R/W0hCounter Reset on Capture Event 1
0h=Disable
1h=Enable
0CAP1POLR/W0hCapture Event 1 Polarity select
0h=Rising edge
1h=Falling edge
ECCTL2
BitFieldTypeResetDescription
15-11RESERVEDR0h
10APWMPOLR/W0hAPWM output polarity select.
This is applicable only in APWM operating mode
0h = Output is active high (Compare value defines high time)
1h = Output is active low (Compare value defines low ti
9CAP_APWMR/W0hCAP/APWM operating mode select
0h = ECAP module operates in capture mode. This mode forces the following configuration. (a) Inhibits TSCTR resets via PRDEQ event. (b) Inhibits shadow loads on CAP1 and 2 registers. (c) Permits user to enable CAP1-4 register load. (d) ECAPn/APWMn pin operates as a capture input.
1h = ECAP module operates in APWM mode. This mode forces the following configuration. (a) Resets TSCTR on PRDEQ event (period boundary). (b) Permits shadow loading on CAP1 and 2 registers. (c) Disables loading of time-stamps into CAP1-4 registers. (d) ECAPn/APWMn pin operates as a APWM outp
8SWSYNCR/W0hSoftware-forced Counter (TSCTR) Synchronizing.
This provides a convenient software method to synchronize some or all ECAP time bases.
In APWM mode, the synchronizing can also be done via the PRDEQ event.
Note: Selecting PRDEQ is meaningful only in APWM mode.
However, you can choose it in CAP mode if you find doing so useful.
0h = Writing a zero has no effect. Reading always returns a zero
1h = Writing a one forces a TSCTR shadow load of current ECAP module and any ECAP modules down-stream providing the SYNCO_SEL bits are 0,0. After writing a 1, this bit returns to a zero
7-6SYNCO_SELR/W0hSync-Out Select
0h = Select sync-in event to be the sync-out signal (pass through)
1h = Select PRDEQ event to be the sync-out signal
2h = Disable sync out signal
3h = Disable sync out sign
5SYNCI_ENR/W0hCounter (TSCTR) Sync-In select mode
0h = Disable sync-in option
1h = Enable counter (TSCTR) to be loaded from CTRPHS register
upon either a SYNCI signal or a S/W force event.
4TSCTRSTOPR/W0hTime Stamp (TSCTR) Counter Stop (freeze) Control
0h = TSCTR stopped
1h = TSCTR free-running
3RE-ARMR/W0hOne-Shot Re-Arming Control, that is, wait for stop trigger.
Note: The re-arm function is valid in one shot or continuous mode.
0h = Has no effect (reading always returns a 0)
1h = Arms the one-shot sequence as follows: 1) Resets the Mod4 counter to zero. 2) Unfreezes the Mod4 counter. 3) Enables capture register loads.
2-1STOP_WRAPR/W0hStop value for one-shot mode.
This is the number (between 1 and 4) of captures allowed to occur before the CAP (1 through 4) registers are frozen, that is, capture sequence is stopped.
Wrap value for continuous mode.
This is the number (between 1 and 4) of the capture register in which the circular buffer wraps around and starts again.
Notes: STOP_WRAP is compared to Mod4 counter and, when equal, the following two actions occur.
(1) Mod4 counter is stopped (frozen), and (2) Capture register loads are inhibited.
In one-shot mode, further interrupt events are blocked until re- armed.
0h = Stop after Capture Event 1 in one-shot mode. Wrap after Capture Event 1 in continuous mode.
1h = Stop after Capture Event 2 in one-shot mode. Wrap after Capture Event 2 in continuous mode.
2h = Stop after Capture Event 3 in one-shot mode. Wrap after Capture Event 3 in continuous mode.
3h = Stop after Capture Event 4 in one-shot mode. Wrap after Capture Event 4 in continuous mode.
0CONT_ONESHTR/W0hContinuous or one-shot mode control (applicable only in capture mode)
0h = Operate in continuous mode
1h = Operate in one-shot mode
ECEINT
BitFieldTypeResetDescription
15-8RESERVEDR0h
7CMPEQR/W0hCounter Equal Compare Interrupt Enable.
6PRDEQR/W0hCounter Equal Period Interrupt Enable.
5CNTOVFR/W0hCounter Overflow Interrupt Enable.
4CEVT4R/W0hCapture Event 4 Interrupt Enable.
3CEVT3R/W0hCapture Event 3 Interrupt Enable.
2CEVT2R/W0hCapture Event 2 Interrupt Enable.
1CEVT1R/W0hCapture Event 1 Interrupt Enable.
0RESERVEDR0h
ECFLG
BitFieldTypeResetDescription
15-8RESERVEDR0h
7CMPEQR0hCompare Equal Compare Status Flag.
This flag is only active in APWM mode.
6PRDEQR0hCounter Equal Period Status Flag.
This flag is only active in APWM mode.
5CNTOVFR0hCounter Overflow Status Flag.
This flag is active in CAP and APWM mode.
4CEVT4R0hCapture Event 4 Status Flag This flag is only active in CAP mode.
3CEVT3R0hCapture Event 3 Status Flag.
2CEVT2R0hCapture Event 2 Status Flag.
1CEVT1R0hCapture Event 1 Status Flag.
0INTR0hGlobal Interrupt Status Flag.
ECCLR
BitFieldTypeResetDescription
15-8RESERVEDR0h
7CMPEQR/W0hCounter Equal Compare Status Flag
0h = Writing a 0 has no effect. Always reads back a 0
1h = Writing a 1 clears the CMPEQ flag condition.
6PRDEQR/W0hCounter Equal Period Status Flag
0h = Writing a 0 has no effect. Always reads back a 0
1h = Writing a 1 clears the PRDEQ flag condition.
5CNTOVFR/W0hCounter Overflow Status Flag
0h = Writing a 0 has no effect. Always reads back a 0
1h = Writing a 1 clears the CNTOVF flag condition.
4CEVT4R/W0hCapture Event 4 Status Flag
0h = Writing a 0 has no effect. Always reads back a 0.
1h = Writing a 1 clears the CEVT4 flag condition.
3CEVT3R/W0hCapture Event 3 Status Flag
0h = Writing a 0 has no effect. Always reads back a 0.
1h = Writing a 1 clears the CEVT3 flag condition.
2CEVT2R/W0hCapture Event 2 Status Flag
0h = Writing a 0 has no effect. Always reads back a 0.
1h = Writing a 1 clears the CEVT2 flag condition.
1CEVT1R/W0hCapture Event 1 Status Flag
0h = Writing a 0 has no effect. Always reads back a 0.
1h = Writing a 1 clears the CEVT1 flag condition.
0INTR/W0hGlobal Interrupt Clear Flag
0h = Writing a 0 has no effect. Always reads back a 0.
1h = Writing a 1 clears the INT flag and enable further interrupts to be generated if any of the event flags are set to 1.
ECFRC
BitFieldTypeResetDescription
15-8RESERVEDR0h
7CMPEQR/W0hForce Counter Equal Compare Interrupt
0h = No effect. Always reads back a 0.
1h = Writing a 1 sets the CMPEQ flag bit.
6PRDEQR/W0hForce Counter Equal Period Interrupt
0h = No effect. Always reads back a 0.
1h = Writing a 1 sets the PRDEQ flag bit.
5CNTOVFR/W0hForce Counter Overflow
0h = No effect. Always reads back a 0.
1h = Writing a 1 to this bit sets the CNTOVF flag bit.
4CEVT4R/W0hForce Capture Event 4
0h = No effect. Always reads back a 0.
1h = Writing a 1 sets the CEVT4 flag bit.
3CEVT3R/W0hForce Capture Event 3
0h = No effect. Always reads back a 0.
1h = Writing a 1 sets the CEVT3 flag bit.
2CEVT2R/W0hForce Capture Event 2
0h = No effect. Always reads back a 0.
1h = Writing a 1 sets the CEVT2 flag bit.
1CEVT1R/W0hAlways reads back a 0.
Force Capture Event 1
0h = No effect.
1h = Writing a 1 sets the CEVT1 flag bit.
0INTR/W0h

使用例

続いて代表的な使用例について見ていく。
簡単なライブラリを作ったので、レジスタのmmapとオフセット計算はライブラリに任せることにする。main関数のみ解説するので、詳細はソースを見てほしい。

PWMの出力(eHPWM)

未調査

任意周波数/デューティー比の出力(eCAP)

PWM output

ECCTL1レジスタは次のような設定となる。

ECCTL1レジスタは次のような設定となる。

周期とデューティー比はCAP1, CAP2で指定する。
Cycle=CAP1[10^-8 sec], Duty retio=CAP2/CAP1

#include 
#include 
#include 

int main(void){
    if(bbb_pwmss_init()){
        fprintf(stderr, "Can not initialize pwmss lib\n");
        return(1);
    }
    ecap_reg *ECAP = (ecap_reg *)(PWMSS[0]+eCAP_off);

    // Set ECCTL1
    ECAP->ECCTL1 = (uint16_t)0;                         // Set 0x48300128 to 0x0
    // Set ECCTL2
    ECAP->ECCTL2 = (uint16_t)(F_CAP_APWM|F_TSCTRRUN);   // Set 0x4830012A to 0x110
    // Set interrupt
    ECAP->ECEINT = (uint16_t)(F_CNTOVF|F_CEVT2);
    // Clear curent status
    ECAP->ECCLR = (uint16_t)0xffff;

    // period = 1msec, duty = 25%
    ECAP->CAP1 = 100000;
    ECAP->CAP2 = 25000;

    bbb_pwmss_free();
    return(0);
}

時間測定/周期測定(eCAP)

Capture modeに設定し、入力信号でTCCTRの値をキャプチャさせる。
シングルキャプチャモードで、TCCTRの値をCAP1, CAP2にキャプチャしこの差が周期となる。
CAP2のキャプチャが完了で、TCCTRのリセットを行い、測定値を読み込んだ後、プログラムで割込みフラグをリセットしRE-ARMで次の測定を開始させる。

TCRRがオーバーフローした際は0に戻るので、この場合は入力信号の周期が長すぎて計測不可であることを示す。

クロック周波数が100MHzでカウンタが32bitあるので、0-1MHz程度まで1%程度の精度で計測する事が可能だ。

ECCTL1レジスタは次のような設定となる。

ECCTL1レジスタは次のような設定となる。

割り込みは使っても使わなくても、ステータスフラグをチェックすれば実装は可能だが、INTフラグを利用した方がプログラムが簡潔に書ける と感じたので、以下のように設定した。割り込みと言っても、INTフラグがセットされるだけでプログラムやOSに割り込みが欠けられるわけでは無い。 PRUや他のペリフェラルと連携させる場合、HW割り込みが有効なケースはあるかもしれない。

#include <stdint.h>
#include <stdio.h>
#include <pwmss.h>

int main(void){
    if(bbb_pwmss_init()){
        fprintf(stderr, "Can not initialize pwmss lib\n");
        return(1);
    }
    ecap_reg *ECAP = (ecap_reg *)(PWMSS[0]+eCAP_off);

    // Set ECCTL1
    ECAP->ECCTL1 = (uint16_t)(F_CAPLDEN|F_CTRRST2);                              // Set 0x48300128 to 0x108
    // Set ECCTL2
    ECAP->ECCTL2 = (uint16_t)(F_TSCTRRUN|F_STOP_WRAP2|F_CONT_ONESHT|F_REARM);    // Set 0x4830012A to 0x13
    // Set interrupt
    ECAP->ECEINT = (uint16_t)(F_CNTOVF|F_CEVT2);
    // Clear curent status
    ECAP->ECCLR = (uint16_t)0xffff;

    while(1){
        if(ECAP->ECFLG & F_INT){
            if(ECAP->ECFLG & F_CNTOVF){ // counter over flow
                printf("0 Hz\n");
            }
            else{
                printf("%.2f Hz\n", (float)AM335x_PWMSS_CLK/(ECAP->CAP2 - ECAP->CAP1));
            }
            ECAP->ECCLR = (uint16_t)0xffff;
            ECAP->ECCTL2 |= (uint16_t)F_REARM;
        }
    }

    // not reach
    bbb_pwmss_free();
    return(0);
}

直交符号のデコード

未調査

ソースファイル

上記のテストプログラムとライブラリ、dtsファイルが含まれる。
pwmss.tar.xz
pwmss_cpp.tar.xz