PWM 割り込み

先日から、PWMの使い方について調べてきました。今日は、PWM の立ち上がり、立ち下がりで割り込みをとる設定についてです。

PWM - Vakna!
PWM その2 - Vakna!

PWM割り込みを使う場合、PWMを使うための設定に加えて、以下の設定が必要です。

割り込みハンドラの登録

driverlib/timer.c のAPI、TimerIntRegister()でハンドラ関数を設定します。

割り込みのエッジ設定

TimerA/B、使う方にあわせてGPTMCTLレジスタのTAEVENT、TBEVENTにエッジ種別を設定します。

エッジ種別
立ち上がりエッジ 0x0
立ち下がりエッジ 0x1
予約 0x2
両エッジ 0x3

これは、TimerControlEvent()で設定可能です。

割り込みイネーブル

こちらも使うタイマーにあわせて、TimerAはGPTMTAMRレジスタのTAPWMIE、TimerBはGPTMTBMRレジスタのTABWMIEを1に設定します。

割り込み有効/無効
PWM割り込み無効 0
PWM割り込み有効 1

こちらは、TimerConfigure()でPWMを設定した場合、即ちTIMER_CFG_A_PWM、TIMER_CFG_B_PWMを設定すると同時に、1が設定されるようになっています。IntMasterEnable() も必要です。


タイマBの割り込みハンドラで、タイマAのPWM dutyを操作するサンプルプログラムを書いてみました。

#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_timer.h"

#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/pin_map.h"
#include "driverlib/sysctl.h"
#include "driverlib/timer.h"

int sysclk = 0;
float ms = 1.0;
unsigned long cycle, duty;
unsigned char cycleScale, dutyScale;

// Timer0 割り込みハンドラ
void Timer0IntHandler(void) {
    // 割り込みステータスクリア
    unsigned long ulStatus = TimerIntStatus(TIMER0_BASE, true);
    TimerIntClear(TIMER0_BASE, ulStatus);

    // Timer0-A の PWM duty を更新
    if (ms < 5.0) ms += 0.05;
    else          ms = 1.0;
    duty = sysclk / 1000 * ms;
    dutyScale = duty >> 16;
    duty &= 0xFFFF;
    TimerPrescaleMatchSet(TIMER0_BASE, TIMER_A, dutyScale);
    TimerMatchSet(TIMER0_BASE, TIMER_A, duty);
}

void main(void) {
    SysCtlClockSet(
        SYSCTL_SYSDIV_2_5|SYSCTL_USE_PLL|SYSCTL_XTAL_16MHZ|SYSCTL_OSC_MAIN);
    sysclk = SysCtlClockGet();

    SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);

    TimerConfigure(
        TIMER0_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PWM | TIMER_CFG_B_PWM);
    TimerControlLevel(TIMER0_BASE, TIMER_BOTH, true);

    // Timer0-B 立ち上がりエッジで割り込みハンドラ Timer0IntHandler を設定
    TimerControlEvent(TIMER0_BASE, TIMER_B, TIMER_EVENT_POS_EDGE);
    TimerIntRegister(TIMER0_BASE, TIMER_B, Timer0IntHandler);

    GPIOPinConfigure(GPIO_PB6_T0CCP0);
    GPIOPinTypeTimer(GPIO_PORTB_BASE, GPIO_PIN_6);
    GPIOPinConfigure(GPIO_PB7_T0CCP1);
    GPIOPinTypeTimer(GPIO_PORTB_BASE, GPIO_PIN_7);

    cycle = sysclk / 1000 * 20;     // Timer0 PWM 周期を 20msec に設定
    cycleScale = cycle >> 16;
    cycle &= 0xFFFF;
    TimerPrescaleSet(TIMER0_BASE, TIMER_BOTH, cycleScale);
    TimerLoadSet(TIMER0_BASE, TIMER_BOTH, cycle);

    duty = sysclk / 1000 * 1;       // Timer0-A PWM duty を 1msec に設定
    dutyScale = duty >> 16;
    duty &= 0xFFFF;
    TimerPrescaleMatchSet(TIMER0_BASE, TIMER_A, dutyScale);
    TimerMatchSet(TIMER0_BASE, TIMER_A, duty);

    duty = sysclk / 1000 * 15;      // Timer0-B PWM duty を 15msec に設定
    dutyScale = duty >> 16;
    duty &= 0xFFFF;
    TimerPrescaleMatchSet(TIMER0_BASE, TIMER_B, dutyScale);
    TimerMatchSet(TIMER0_BASE, TIMER_B, duty);

    // TIMER_CAPB_EVENT 割り込み有効化
    IntMasterEnable();
    TimerIntEnable(TIMER0_BASE, TIMER_CAPB_EVENT);
    TimerEnable(TIMER0_BASE, TIMER_BOTH);

    while (1) {}
}