LPC810M021FN8 (6) -- SCT を PWM として使う (3)

LPC8xx に搭載されている SCT (State Configurable Timer) を PWM として応用する方法について述べます。
「ステート」は全く使用しなくても PWM は実現できますし、「キャプチャ」機能は PWM への応用には関係しないので、それらの機能については深入りしません。
まず、SCT は

  • 16 ビット・カウンタ × 2 本
  • 32 ビット・カウンタ 1 本 (UNIFY モード)

のいずれかのモードに設定できます。
ユニファイ・モードの場合に 32 ビット幅のレジスタ 1 本が占めるアドレス・スペースを、16 ビット・モードの場合には下位 16 ビット、上位 16 ビットに分割してアクセスする形になります。
たとえば、 PWM のデューティー値を設定する対象となるマッチ・リロード・レジスタへのアクセスは、それぞれ、

  LPC_SCT->MATCHREL[n].U = (uint32_t) 0;
  LPC_SCT->MATCHREL[n].L = (uint16_t) 0;
  LPC_SCT->MATCHREL[n].H = (uint16_t) 0;

のような形で表現します。
ここで、(uint16_t) のような「キャスト」は、単にデータのビット幅を明示するだけの目的で付けたもので、実際には必要ありません。
LPC8xx に搭載されている SCT の「リソース」は、

  • 4 入力 (CTIN_0 〜 CTIN_3)
  • 4 出力 (CTOUT_0 〜 CTOUT_3)
  • 5 マッチ/キャプチャ・レジスタ (MATCH0 〜 MATCH4)
  • 6 イベント (EV0 〜 EV5)
  • 2 ステート

となっています。
SCT は LPC43xx などにも搭載されていますが、そちらは

  • 8 入力 (CTIN_0 〜 CTIN_7)
  • 16 出力 (CTOUT_0 〜 CTOUT_15)
  • 16 マッチ/キャプチャ・レジスタ (MATCH0 〜 MATCH15)
  • 16 イベント (EV0 〜 EV15)
  • 32 ステート
  • DMA 起動可能

が 2 系統 (うち 1 系統は「dither engine」付き) という「豪華版」です。
SCT では、カウンタをフリーランで走らせるのではなく、一定の周期で繰り返させるためにカウンタ値が特定の値になったらカウンタをリセットすることを「リミット」(limit) と呼んでいます。
カウンタはアップ・カウンタ (LPC_SCT->CTRL レジスタの BIDIR ビット = 0) あるいはアップ・ダウン・カウンタ (双方向モード、BIDIR = 1) のいずれかのモードで動作させます。
「Single Edge PWM mode」の実現には、アップ・カウンタ・モード (BIDIR = 0) を使います。
タイミング・チャートを下に示します。

カウント値が、縦軸のラベルに「limit」として示した値に達すると、カウンタがリセットされ、0 に戻ります。
このとき、マッチ・リロード (MATCHREL) ・レジスタに保持されていた値が、それぞれ対応するマッチ (MATCH) ・レジスタに転送され、マッチ・レジスタの値が一斉に更新されます。
タイマ動作中はマッチ・レジスタへの直接の書き込みは禁止され、書き込めるのはリロード・レジスタのほうになります。
LPC11xx のタイマの PWM 機能では、このリロード (バッファ) レジスタがなく、常時カウンタ値と比較されているマッチ・レジスタに直接書き込む形となるので、書き込みタイミングにより意図しない不正な PWM 波形が 1 周期だけ出力される場合がありました。
リミット値の指定にはマッチ・レジスタのいずれかが使われ、実際には、後述する「イベント」を定義して、そのイベントで「リミット」動作を行わせるように指定します。
また、「オート・リミット」という機能もあって、指定すると、イベント定義の設定なしに暗黙のうちにリミット・レジスタとして MATCH0 が使われ、リミットが掛けられます。
オート・リミットは「イベント」ではないので、出力を変化させたり、割り込みを掛けたり、ステートを進めたりはできません。
「CV」のように、ほぼ「直流」で細かい波形が問題にならない場合には、オート・リミットを使い、任意のタイミングでリロード・レジスタを更新しても不都合はありません。
オーディオ出力のために PWM を使う場合には、サンプリング・タイミングに同期して、きちんとリロード・レジスタの値を更新することが求められるため、リミットのための「イベント」を定義し、カウンタのクリアと同時に割り込みを発生させる必要があります。
リミットに使うマッチ・レジスタ (およびリロード・レジスタ) に設定する値を (N - 1) とすると、カウントは
0, 1, ... ,(N - 2), (N - 1), 0, 1, ...
と進み、PWM 周期は N になります。
「Double Edge PWM mode」の実現には、アップ・ダウン・(双方向) カウンタ・モード (BIDIR = 1) を使います。
そのタイミング・チャートを下に示します。

アップ・カウント状態でカウンタがリミット値に達すると、「リミット動作」としてはカウンタをゼロクリアするのではなく、カウンタの状態が切り替わり、カウント・ダウンを始めます。
カウント・ダウンが進んで 0 に達すると、マッチ・レジスタのリロードが行われ、アップ・カウント状態に切り替わります。
リミットに使うマッチ・レジスタ (およびリロード・レジスタ) に設定する値を (N - 1) とすると、カウントは
0, 1, ... ,(N - 2), (N - 1), (N - 2), (N - 3), ... , 1, 0, 1, ...
と進み、

  • 0 から (N - 1) までが N クロック
  • (N - 2) から 1 までが (N - 2) クロック

であることから、PWM 周期は N + (N - 2) = 2(N - 1) となります。
双方向モードでもオート・リミット機能が使えます。
リミットを全く設定しない状態でも、16 ビット・モードでのカウンタの最大値 0xFFFF あるいは、32 ビット・モードでのカウンタの最大値 0xFFFFFFFF に達すると、自動でカウント・ダウンに切り替わり、カウンタは 0 と最大値の間を往復する形になります。
ソフトウェアからリロード・レジスタを更新するタイミングとしては、カウント 0 が最も望ましいのですが、イベントではないので割り込みを発生させることはできません。
リミットを「イベント」として定義し、リミット時に割り込みを発生させます。
この場合 PWM 半周期後のカウント 0 でリロードが行われてしまうので、それまでの間にリロード・レジスタを更新しなかればなりません。
次回に続きます。