信号処理 入門

1-5 A/D変換プログラム
公開講義(組込みプロセッサによる音信号処理入門)
岐阜県情報技術研究所
田畑 克彦
1
A/D変換
 アナログ信号をディジタル信号に変換する
 アナログの電圧値を測定して、その値をデータレジスタに格納
アナログ信号
標本化
標本化
アナログ信号
量子化
ディジタル信号
量子化
ディジタル信号
2
A/Dコンバータの概要
 SH7144FのA/Dコンバータ
 分解能:10ビット
 入力チャネル:
 8チャネル (2個の独立したA/D変換モジュール内蔵)A/D0, A/D1
 変換時間:1チャネル当たり5.4μs(Pφ=25MHz動作時),6.7μs(Pφ=20MHz動作時)
 動作モード:3種類
 シングルモード:1チャネルのA/D変換
 連続スキャンモード:1~4チャネルの繰り返しA/D変換
 1サイクルスキャンモード:1~4チャネルの連続A/D変換
 データレジスタ:
 A/D変換結果は各入力チャネルに対応した16ビットデータレジスタに格納
 サンプル&ホールド機能付き
 A/D変換開始方法:3種類
 ソフトウェア
 マルチファンクションタイマパルスユニット(MTU)による変換開始トリガを選択可能
 外部トリガ信号
 割り込み要因
 A/D変換終了割り込み要求(ADI)を発生
 入力電圧-変換値
 0V :0
 3.3V:210 -1= 1023 bit = 0x3ff bit (max)
3
A/D データレジスタ0~7(ADDR0~
ADDR7)
 変換結果が格納される
 変換データは上位10ビットに格納され,下位6ビットには常に0が
補充される
ビット
15
14
13
12
11
10
9
10 ビットのデータ
8
7
6
5
4
3
2
1
0
0
0
0
0
0
0
4
A/D コントロール/ステータスレジスタ
(ADCSR)
 動作モードや割り込みなどの設定と,現在の状態フラグ
 シングルモード
 指定された1 チャネルのアナログ入力を1 回A/D 変換
1.
2.
3.
4.
MTUや外部トリガ入力によってADCRのADSTビットが1にセットされると選択
されたチャネルのA/D変換を開始
A/D変換結果をA/Dデータレジスタに転送
A/D変換終了後,ADCSRのADFビットが1にセットされる.このとき,ADIEビッ
トが1にセットされているとADI割り込み要求を発生
ADSTビットはA/D変換中は1を保持し,変換が終了すると自動的にクリアさ
れてA/D変換器は待機状態になる
 連続スキャンモード
 指定されたチャネルのアナログ入力を順次連続してA/D 変換
5
ADCR,ADTSR
 その他のレジスタの設定
 ADCR(コントロールレジスタ)
 変換クロックや変換開始などの設定
 ADTSR(外部トリガセレクトレジスタ)
 外部からの信号を変換開始のトリガにする場合の設定用
 スタンバイ設定
 MTUと同様
6
例題1-5-1:電圧表示プログラム
 可変抵抗で変化する電圧を取得し,その電圧をLED4ビットで、
2進数表示するプログラム
 仕様




MTU4を使用し,定期的にA/D変換を行う
使用A/DコンバータはAD1
信号は AN4より入力
サンプリング・レート 48kHz
7
プログラムの概要
 A/Dコンバータ
 チャネル0,シングル・モード
 サンプリング・レート 48kHz
 MTUのコンペアマッチにより起動
 MTUはコンペアマッチでA/Dコンバータを起動できる
 処理の流れ
 タイマのコンペアマッチによりA/D変換スタート
 A/D変換終了割り込みで処理スタート
 取得した電圧をLEDで表示
8
プログラムの流れ
init_ad()
main()
初期化
ポートレジスタ設定
(データシート17.1.9)
ADCの初期化
MTUの初期化
while(1)
初期化
動作の設定
変換終了で割り
込み
(データシート15.3)
init_mtu()
割り込み処理
int_adi1()
初期化
TGRAのコンペア
マッチでAD変換
スタート
電圧に応じて
LEDを表示
MTUスタート
9
タイムチャート
 プログラムの処理の時間経過
 メインの処理(割り込みハンドラ)以外に,AD変換処理,割り込み処理(レジ
スタ退避・復帰)
 A/DコンバータをMTUから自動で起動
 次の回のAD変換の間も処理を継続可能
コンペアマッチ
A
D
コンペアマッチ
割
り
込
み
A
D
割
り
込
み
メイン処理
10
サンプリング周波数
 サンプリング(標本化)周波数から設定値を求める
 サンプリング周波数=MTUの割り込み周期
 今回は,割り込み周期はTGRAで設定
 TGRAの設定方法
 TGRA=(カウンタ周波数/サンプリング周波数)-1
 -1は,マッチの次のカウント時にクリアされるため
 今回の場合:48kHzサンプリング
 24MHz(Pφ/1)でカウント(MTU4.TCR.BIT.TPSC = 0;)
 カウント回数は24MHz/48kHz=500
 よってTGRAに499を設定( MTU4.TGRA = 499; )
11
A/D変換結果のビット配置
 A/Dコンバータの変換結果のビットシフト
 上位4ビットをPE11~14へ
A/D変換の結果は上位10ビットに格納される
16
9
ADDR 4
8
8
7
6
5
4
3
2
1
1
0
input  ADDR4  6;
下位ビットにシフトする
16
8
9
8
7
上位4ビットを利用
1
6
5
4
3
2
PE
15
0
input  3;
8
PE.BYTE.H
1
1
9
8
7
6
PE
14
PE
13
PE
12
PE
11
PE
10
PE
9
PE
8
12
割り込みハンドラの設定
 MTUの場合と同様に,A/Dコン
バータの変換終了割り込みの割
り込みハンドラを設定
 intprg.c
 全ての割り込み要因に対するハ
ンドラの設定が,vect.hと
vecttbl.c,intprg.cに書かれてい
る
 vect.h
 各関数が割り込みハンドラであ
るとコンパイラに示すための
pragma宣言
…
// 137 A/D ADI1
//追加
void int_adi1();
void INT_ADI1(void){
int_adi1();
}
//コメントアウト
//void INT_ADI1(void){/* sleep(); */}
…
 vecttbl.c
 ベクタテーブルの宣言
 intprg.c
 vect.hで書かれた各関数の実体
13
電圧表示プログラム(1/3)
 MTU4の初期化関数




MTU回路の起動
立ち上がりエッジでカウント
TGRAコンペアマッチでクリア
クロックサイクルの設定
void init_mtu()
{
MST.CR2.BIT._MTU = 0; //MTUを起動
//立ち上がりエッジ
MTU4.TCR.BIT.CKEG = 0;
//TGRAのコンペアマッチでクリア
MTU4.TCR.BIT.CCLR = 1;
//P_phi/1(24MHz)でカウント
MTU4.TCR.BIT.TPSC = 0;
//24Mhz / 48kHz = 500
MTU4.TGRA = 499;
//カウンタを0に
MTU4.TCNT = 0;
 24MHz
 TGRAの値を設定
 1秒に48000回サンプリング
 24MHz / 48kHz – 1 = 499
 通常動作
 TGRAマッチでA/Dコンバータを
起動
 タイマスタート
//通常動作(16ビットタイマー)
MTU4.TMDR.BIT.MD = 0;
//TGRAのコンペアマッチでAD変換開始
MTU4.TIER.BIT.TTGE = 1;
MTU.TSTR.BIT.CST4 = 1; //MTU4をスタート
}
14
電圧表示プログラム(2/3)
 A/Dコンバータの初期化関数







AD1回路の起動
シングルモード
AN4入力
変換終了で割り込み
1サイクル・スキャン
変換時間の設定
MTUトリガによる起動を許可
 メイン関数
 LEDポートの設定
 割り込みマスクのクリア
 A/Dコンバータの初期化関数の呼
び出し
 MTUの初期化関数の呼び出し
 無限ループ
void init_ad()
{
MST.CR2.BIT._AD1 = 0; //AD1を起動
AD1.ADCSR.BIT.ADM = 0; //シングルモード
AD1.ADCSR.BIT.CH = 0; //AN4入力
AD1.ADCSR.BIT.ADIE = 1; //割り込み許可
INTC.IPRG.BIT._AD = 1; //AD割り込みの優先度を1に
AD1.ADCR.BIT.ADCS = 0; //ワンサイクルスキャン
AD1.ADCR.BIT.CKS = 3; //P_phi/4時間で変換
AD1.ADCR.BIT.TRGE = 1; //トリガによる開始は有効
AD1.ADTSR.BIT.TRGS = 2; //MTUトリガ起動を許可
}
void main(void)
{
//初期化
PFC.PEIORL.BIT.B14 = 1; //PE14を出力に設定
PFC.PEIORL.BIT.B13 = 1; //PE13を出力に設定
PFC.PEIORL.BIT.B12 = 1; //PE12を出力に設定
PFC.PEIORL.BIT.B11 = 1; //PE11を出力に設定
set_imask(0); //割り込みマスクをクリア
init_ad(); //ADコンバータの初期化
init_mtu(); //MTUの初期化
while (1);
}
15
電圧表示プログラム(3/3)
 割り込みハンドラ
 A/D変換終了フラグのクリア
 A/D変換結果の取得
 ビットシフトで場所をあわせ,
ビット反転して表示
void int_adi1()
{
int input;
AD1.ADCSR.BIT.ADF = 0; //AD変換終了フラグのクリア
input = AD1.ADDR4.WORD >> 6; //変換結果の取得
PE.DRL.BYTE.H = ((~(input >> 3)) & 0x78) | (PE.DRL.BYTE.H
& 0x87);//ビット表示(ビット反転)
}
 0で点灯のため
 メイン関数
 LEDポートの設定
 割り込みマスクのクリア
 A/Dコンバータ初期化関数の呼び
出し
 MTUの初期化関数の呼び出し
 無限ループ
void main(void)
{
//初期化
PFC.PEIORL.BIT.B14 = 1; //PE14を出力に設定
PFC.PEIORL.BIT.B13 = 1; //PE13を出力に設定
PFC.PEIORL.BIT.B12 = 1; //PE12を出力に設定
PFC.PEIORL.BIT.B11 = 1; //PE11を出力に設定
set_imask(0); //割り込みマスクをクリア
init_ad(); //ADコンバータの初期化
init_mtu(); //MTUの初期化
while (1); }
16
演習1-5-2:電圧表示方法の変更
 入力された電圧を,2進数表現ではなく,LEDの個数(0~4個の5
段階)で表示する
 電圧が高くなるほど,多くのLEDを表示する
 変更内容
 入力値のビットをそのままLEDに出力するのではなく,入力値に応じて点灯
するLEDを変更する
17
例題1-5-3:音量表示プログラム
 A/Dコンバータを用いてPCから音を入力し,大きな音が入力され
たらLEDを点灯するプログラム
 例題1-5-1と基本は同じ
 電圧ではなく音量でLED点灯・消灯を判断する
 LED表示は1 ビット
 仕様





MTU4を使用し,定期的にA/D変換を行う
使用A/DコンバータはAD0
信号は AN0より入力
サンプリング・レート 48kHz
振幅(電圧-平均)の二乗和が
閾値以上の場合「大きな音」とする
18
プログラムの概要
 処理の流れ





タイマのコンペアマッチによりA/D変換スタート
A/D変換終了割り込みで処理スタート
最初の8000回の割り込みで平均値を計算
以後は1000回ずつパワーを計算し,大きな音の有無をチェック
次の1000回の間,LEDを以下の状態に
 音は大きい:点灯
 音は小さい:消灯
19
プログラムの流れ
init_ad()
main()
初期化
ポートレジスタ設定
(データシート17.1.9)
ADCの初期化
MTUの初期化
while(1)
初期化
動作の設定
変換終了で割り
込み
(データシート15.3)
init_mtu()
割り込み処理
int_adi1()
初期化
TGRAのコンペア
マッチでAD変換
スタート
電圧に応じて
LEDを表示
MTUスタート
20
割り込みハンドラの設定
 AD1からAD0に変更
 INT_ADI0();
…
// 136 A/D ADI0
//追加
void int_adi0();
void INT_ADI0(void){int_adi0();}
//コメントアウト
//void INT_ADI0(void){/* sleep(); */}
…
21
音量表示プログラム(1/4)
 MTU4の初期化関数




MTU回路の起動
立ち上がりエッジでカウント
TGRAコンペアマッチでクリア
クロックサイクルの設定
void init_mtu()
{
MST.CR2.BIT._MTU = 0; //MTUを起動
//立ち上がりエッジ
MTU4.TCR.BIT.CKEG = 0;
//TGRAのコンペアマッチでクリア
MTU4.TCR.BIT.CCLR = 1;
//P_phi/1(24MHz)でカウント
MTU4.TCR.BIT.TPSC = 0;
//24Mhz / 48kHz = 500
MTU4.TGRA = 499;
//カウンタを0に
MTU4.TCNT = 0;
 24MHz
 TGRAの値を設定
 1秒に48000回サンプリング
 24MHz / 48kHz - 1 = 499
 通常動作
 TGRAマッチでA/Dコンバータを
起動
 タイマスタート
//通常動作(16ビットタイマー)
MTU4.TMDR.BIT.MD = 0;
//TGRAのコンペアマッチでAD変換開始
MTU4.TIER.BIT.TTGE = 1;
MTU.TSTR.BIT.CST4 = 1; //MTU4をスタート
}
 例題1-4-1と同じ
22
音量表示プログラム(2/4)
 A/Dコンバータの初期化関数







AD0回路の起動
シングルモード
AN0入力
変換終了で割り込み
1サイクル・スキャン
変換時間の設定
MTUトリガによる起動を許可
 メイン関数
 LEDポートの設定
 割り込みマスクのクリア
 A/Dコンバータの初期化関数の呼
び出し
 MTUの初期化関数の呼び出し
 無限ループ
void init_ad()
{
MST.CR2.BIT._AD0 = 0; //AD0を起動
AD0.ADCSR.BIT.ADM = 0; //シングルモード
AD0.ADCSR.BIT.CH = 0; //AN0入力
AD0.ADCSR.BIT.ADIE = 1; //割り込み許可
INTC.IPRG.BIT._AD = 1; //AD割り込みの優先度1
AD0.ADCR.BIT.ADCS = 0; //ワンサイクルスキャン
AD0.ADCR.BIT.CKS = 3; //P_phi/4時間で変換
AD0.ADCR.BIT.TRGE = 1; //トリガによる開始は有効
AD0.ADTSR.BIT.TRGS = 2; //MTUトリガ起動を許可
}
void main(void)
{
//初期化
PFC.PEIORL.BIT.B15 = 1; //PE15を出力に設定
set_imask(0); //割り込みマスクをクリア
init_ad(); //ADコンバータの初期化
init_mtu(); //MTUの初期化
while (1);
}
23
音量表示プログラム(3/4)
 割り込みハンドラ(前半)
 A/D変換終了フラグのクリア
 A/D変換結果の取得
 16ビットレジスタの上位10ビット
にデータが収納されているので,
右に6ビットシフト
 音の平均値の算出
 A/Dの値を足し合わせていく
 8000回分になったら平均値を
求める
 平均値算出フラグのクリア
 回数の変数をクリア
void int_adi0()
{
static int time = 0; //変換回数
static char calc_avg_flag = 1; //平均値計算フラグ
static int avg = 0; //音の平均値
static int power = 0; //パワー
int input;
AD0.ADCSR.BIT.ADF = 0; //AD変換終了フラグのクリア
input = AD0.ADDR0.WORD >> 6; //変換結果の取得
if (calc_avg_flag) {
//音の平均値の算出
avg += input;
if (time++ == 8000) {
//8000回の平均値を求め,フラグをクリア
avg /= 8000;
calc_avg_flag = 0;
time = 0;
}
}
24
音量表示プログラム(4/4)
 割り込みハンドラ(後半)
…続き
//音検出
power += (input-avg) * (input-avg);
if (++time == 1000) {
//1000回の平均で音の有無をチェック
if (power / 1000 > 0x100) {
PE.DRL.BIT.B15 = 0; //LED ON
} else {
PE.DRL.BIT.B15 = 1; //LED OFF
}
power = 0;
time = 0;
}
 音検出
 パワーを足し合わせていく
 平均値との差の二乗
 1000回分たまったら平均を求め,
音の有無をチェック
 パワーの大きさが一定値以上な
らばLEDを点灯
 大きさが一定値以下ならLEDを
消灯
 パワーと計測回数のクリア
}
}
25
演習1-5-4:音量レベル表示
 入力された音の大きさに応じて複数のLEDを表示する
 PE15のLEDで1bit表示からPE11~14の4bit表示に変更する
 変更内容
 演習1-5-2と同様
26