LPC810メモ:SCTの例その2(音を鳴らすなど)
SCTの機能をいろいろ試した例。
前提とする環境はこちら→LPC810メモ 共通の準備
SCT全般のメモはこちら→LPC810メモ:SCTimer/PWM (SCT)について
試してみたかった機能は以下。
- 16bitのタイマ2本(L/H)に分けて使う
- bidirectinalモード(上限に達したらカウントダウンして、0とLIMITを往復するやつ
- 入力pinの状態に応じたevent発生
- 割り込み
- stateの変更
実現した内容は以下。
- 救急車風の「ピーポーピーポー」という音を鳴らす。
- ボタンを押すと音が止まる、もう一度押すと再開
仕組みとしては以下。なお、stateは実質0,1しか使えないようだが、タイマL,Hそれぞれについて0,1が使える模様。2x2で4状態と言うこともできる気がする。
- タイマL
- match0で決まる周波数に応じて音を鳴らす(4番pinが出力、圧電スピーカをつなぐ)
- ボタンを押されると、state0,1を切り替える
- 音は、state0の時しか鳴らない
- タイマH
- match0で決まる間隔(0.5秒)毎に、state0,1を切り替える。
- stateが切り替わる際に、タイマLのmatch0の値を書き換えて、周波数を変更。
- これにより、「ピー」と「ポー」を入れ替える。
サンプルコード
#include "LPC8xx.h" int main(void) { // SWMのclockを有効化 LPC_SYSCON->SYSAHBCLKCTRL |= (1<<7); // 5番pin(PIO_1)にSCT入力の0番(CTIN_0) を設定 // UM10601 9.5.6 Pin assign register 5 LPC_SWM->PINASSIGN5 = 0x01ffffffUL; // 4番pin(PIO_2)にSCT出力の0番(CTOUT_0) を設定 // UM10601 9.5.7 Pin assign register 6 LPC_SWM->PINASSIGN6 = 0x02ffffffUL; // RESET 以外の無効化 LPC_SWM->PINENABLE0 = 0xffffffbfUL; // UM10601 10.3 Basic configuration // に従った準備 // SCTのclockを有効化(UM10601 4.6.13 System clock control register) LPC_SYSCON->SYSAHBCLKCTRL |= (1<<8); // Clear the SCT peripheral reset using the PRESETCTRL register (Table 19). LPC_SYSCON->PRESETCTRL &= ~(0x1<<8); LPC_SYSCON->PRESETCTRL |= (0x1<<8); // 今回は割り込みを使うので以下を設定 // UM10601 3.4.1 Interrupt Set Enable Register 0 register NVIC->ISER[0] = (0x1 << 9); // 以下、SCTの設定 // UM10601 10.6.1 SCT configuration register LPC_SCT->CONFIG = (0 << 0 ) // UNIFY = 0 -> 16bitのタイマ2本(L,H)で利用する | (1 << 17) // AUTOLIMIT_L = 1 -> matchの0番(後で定義)を、カウントアップの上限とする | (1 << 18); // AUTOLIMIT_H = 1 -> matchの0番(後で定義)を、カウントアップの上限とする // 以下、タイマL関連の設定 LPC_SCT->CTRL_L |= (1 << 4) // BIDIR_L = 1 ->bidirectional mode | (60 - 1 ) << 5; // PRE_L = 60 -> 60クロックで1カウント。bidirectionalなので、100KHz。 // カウンタにmatchする値を定義 // UM10601 10.6.20 SCT match reload registers 0 to 4 (REGMODEn bit = 0) LPC_SCT->MATCHREL[0].L = (uint16_t)(100000 / 494); // 494Hz(ピーポーの「ピー」) LPC_SCT->MATCHREL[1].L = 0; // event0番(match 0、LIMITに達した時に発生) // 10.6.22 SCT event state mask registers 0 to 5 // 10.6.23 SCT event control registers 0 to 5 LPC_SCT->EVENT[0].STATE = 0x01; // state0で発生 LPC_SCT->EVENT[0].CTRL = (0 << 0) // MATCHSEL = 0 -> match0に対応 | (0 << 4) // HEVENT = 0 -> タイマLに対応 | (1 << 12); // COMBMODE = 1 -> match だけに対応 // event1番(match 1、カウンタが0にもどって発生) LPC_SCT->EVENT[1].STATE = 0x01; // state0で発生 LPC_SCT->EVENT[1].CTRL = (1 << 0) // MATCHSEL = 1 -> match1に対応 | (0 << 4) // HEVENT = 0 -> タイマLに対応 | (1 << 12); // COMBMODE = 1 -> match だけに対応 // event2番(state0時のin1の立下り、state1に遷移) LPC_SCT->EVENT[2].STATE = 0x01; // state0で発生 LPC_SCT->EVENT[2].CTRL = (0 << 4) // HEVENT = 0 -> タイマLに対応 | (0 << 6) // IOSEL 入力1に対応 | (2 << 10) // IOCOND fallに対応 | (2 << 12) // COMBMODE = 2 -> I/O condition だけに対応 | (1 << 14) // STATELD = 1 -> stateをSTATEVに設定 | (1 << 15); // STATEV = 1 -> state を 1に変更。 // event3番(state1時のin1の立下り、state0に遷移) LPC_SCT->EVENT[3].STATE = 0x02; // state1で発生 LPC_SCT->EVENT[3].CTRL = (0 << 6) // IOSEL 入力1に対応 | (2 << 10) // IOCOND fallに対応 | (2 << 12) // COMBMODE = 2 -> I/O condition だけに対応 | (1 << 14) // STATELD = 1 -> stateをSTATEVに設定 | (0 << 15); // STATEV = 0 -> state を 0に変更。 // event2番でstop LPC_SCT->STOP_L = 1 << 2; // event3番でstart LPC_SCT->START_L = 1 << 3; // 出力の定義 // UM10601 10.6.24 SCT output set registers 0 to 3 // UM10601 10.6.25 SCT output clear registers 0 to 3 // 出力0番 LPC_SCT->OUT[0].SET = (1 << 0); // event 0 でset LPC_SCT->OUT[0].CLR = (1 << 1); // event 1 でclear // タイマL関連の設定、ここまで。 // 以下、タイマH関連の設定 LPC_SCT->CTRL_H |= (0 << 4) // BIDIR_L = 0 -> こちらはbidirectional modeにしない | (240 - 1 ) << 5; // PRE_L = 240 -> 240クロックで1カウント、50KHz相当。 // match0の設定 LPC_SCT->MATCHREL[0].H = 50000 / 2; // 2Hz // event4(state0でmatch 0に達した時に発生、割り込みを起こしてstate1に遷移) LPC_SCT->EVENT[4].STATE = 0x01; // state0で発生 LPC_SCT->EVENT[4].CTRL = (0 << 0) // MATCHSEL = 0 -> match0に対応 | (1 << 4) // HEVENT = 1 -> タイマHに対応 | (1 << 12) // COMBMODE = 1 -> match だけに対応 | (1 << 14) // STATELD = 1 -> stateをSTATEVに設定 | (1 << 15); // STATEV = 1 -> state を 1に変更。 // event4(state1でmatch 0に達した時に発生、割り込みを起こしてstate0に遷移) LPC_SCT->EVENT[5].STATE = 0x02; // state1で発生 LPC_SCT->EVENT[5].CTRL = (0 << 0) // MATCHSEL = 0 -> match0に対応 | (1 << 4) // HEVENT = 1 -> タイマHに対応 | (1 << 12) // COMBMODE = 1 -> match だけに対応 | (1 << 14) // STATELD = 1 -> stateをSTATEVに設定 | (0 << 15); // STATEV = 0 -> state を 0に変更。 // event4,5発生時には割り込みを発生させる。 // 10.6.14 SCT flag enable register LPC_SCT->EVEN = 1 << 4 | 1 << 5; // 以上で設定完了、haltを解除してstart /// UM10601 10.6.2 SCT control register LPC_SCT->CTRL_L &= ~(1 << 2); // HALT_L = 0 LPC_SCT->CTRL_H &= ~(1 << 2); // HALT_H= 0 return 0 ; } extern "C" { // SCT割り込み用のハンドラを定義 // 関数名は自動生成されたcr_startup_lpc8xx.cの中で定義されているもの void SCT_IRQHandler(void) { // どのイベントに対応する割り込みかで分岐 // 10.6.15 SCT event flag register if(LPC_SCT->EVFLAG & (1 << 4)) { // タイマLのmatchを修正 LPC_SCT->MATCHREL[0].L = (uint16_t)(100000 / 494); // 494Hz(ピーポーの「ピー」) // イベントを処理した旨を設定 LPC_SCT->EVFLAG = 1 << 4; } else if(LPC_SCT->EVFLAG & (1 << 5)) { // タイマLのmatchを修正 LPC_SCT->MATCHREL[0].L = (uint16_t)(100000 / 392); // 392Hz(ピーポーの「ポー」) // イベントを処理した旨を設定 LPC_SCT->EVFLAG = 1 << 5; } return; } }
接続
- 電源onで「ピーポーピーポー」なり始める。
- 圧電スピーカは、4番pinとGNDにつないである。
- 圧電スピーカはこれを利用
補足/雑感
- イベント2,3でタイマを止めているが、考えてみると不要か。event0,1はstate1では発生しないため、どうせ音はならない。
- これの前にbidirectionalモードを32bitタイマ(UNIFY = 1)で動かそうとして失敗。なぜだかは理解できてない。
- スイッチがプルアップして、押すとLOWになる方向なのは、5番を電源on時にLOWにしたくないから。
- AUTOLIMITを、L,Hそれぞれ設定する必要があることに気づかず、ちょっとハマった。
- 知識不足故に用途は良くわからないが、SCTの使い方自体はだいたいわかった気がする。
- ただしcaptureっていうのは使ってみたい。
- 割り込みを使ってみて思ったのが、なんとなく、SCTで割り込みを使ったら負けな気がした。