<V.3版>
SPI 制御による
DAコンバータ出力
(割込みハンドラ直接記述編)
(→プロジェクトファイル(Harmony Ver.3版 MHC v3.6.0) ダウンロード)
PIC32MZを使い、SPI モジュールを内臓したマイクロチップのD/AコンバータMCP4922をSPI制御してD/A変換を行った例を紹介します。
<仕様>
・ DAコンバータに正弦波電圧を出力する。
・ PICはPIC32MZ2048EFH100を用い、DAコンバータはMCP4922を用いる。
・ 1度毎の正弦波テーブルを生成し、割り込みによりこのデータを500Hzで(2 msec毎に)サンプリングしてSPI通信でD/Aコンバータ
MCP4922に伝送する。
SPI諸元(PIC側):
モード: マスターモード
SPIクロック周波数: 10MHz
データ幅: 16ビット
データモード: IDLE Low ACTIVE High
遷移: クロックがACTIVE(High) → IDLE(Low)に変化した時、MCP4922レジスタデータ変化
データ抽出タイミング: データの後縁
・ MCP4922(電源電圧+3.3V)からは、1.39Hz(注)、Vp-p 2.7V、分解能12ビットの正弦波電圧を出力する。
出力ポートはVoutAとする。
(注)1.39Hz = 500KHz ÷ 360
・ Harmonyの スタティックSPIライブラリとスタティクタイマライブらを用いる。
<回路図>( → PDFファイル)
<外観>
PIC32MZ評価ボード(→購入方法)を使った実験品の外観です。
汎用モジュール評価ボード(段積みボード)には本テーマと関係ない部品が多々実装されています。
DAコンバータ MCP4922の 端子VoutAの出力電圧 |
![]() |
1V/div 200msec/div |
<解説> 記載してある内容は要点だけです。 詳細はプロジェクトファイルを精読願います。
■ ステップ1: MHC作成
■ ステップ2: ソースコードへの追加
■ app.h への追加
app.hに以下を追加するのは、 遅延関数delay_ms( )を interrupts.cで使用する際、 コンパイラで暗黙宣言エラー対策です。
すなわち app.h app.cで delay_ms( )を定義して コンパイルで error: implicit declaration of function 'delay_ms' といったエラーが
発生しないようにしています。
void delay_us(volatile unsigned int usec);
void delay_ms(volatile unsigned int msec);
以下、 app.h 全文
■ app.cに、青字部分を追加します。
① delay_us( )、delay_ms( ) という NOPを使った 1μsec 、1msec単位の遅延関数をつくります。
void delay_us(volatile unsigned int usec) //1μsec遅延
{
volatile int count;
……
……
② 正弦波形出力のテーブル作成用の関数を作成します。
void SinTable() //Sin のテーブル作成
{
short int i;
float PAI = 3.1416;
……
……
③ コールバック関数によるLEDのON/OFF
このコールバック関数がなくても、本題の正弦波描画はinterrupts.cのコードで実行できます。
void TMR1_Callback_Func(uint32_t status, uintptr_t context) //コールバック関数
//2msec毎に呼び出される
{
if(LED == false)
{
LED = true;
LED1_Set(); //RG15: LED点灯 //plib_gpio.hで定義
// GPIO_PinSet(GPIO_PIN_RG15); //Harmonyライブラリの関数で制御
// LATGbits.LATG15 = 1; //レジスタ直接制御
}
else
{
LED = false;
LED1_Clear(); //RG15: LED消灯
// GPIO_PinClear(GPIO_PIN_RG15);
// LATGbits.LATG15 = 0;
}
/LED1_Toggle(); //RG15:LED 点灯/消灯
}
④ APP_Initialize ( )の中で、 Sin波形のテーブルを作成後、インターバルタイマを ONにします。
SinTable(); //Sinテーブル作成
TMR1_Start(); //タイマ1 スタート
//T1CONbits.ON = 1; //レジスタ直接制御
⑤ APP_Tasks ( )のはじめで、コールバック関数を設定し、SPIのハンドルを生成します。
SPIのハンドルは interrupts.cの中で使用します。
TMR1_CallbackRegister(TMR1_Callback_Func, NULL); //コールバック関数設定
spi_Handle = DRV_SPI_Open(DRV_SPI_INDEX_0, DRV_IO_INTENT_WRITE); //SPIハンドル生成
以下、app.c 全文
■ interrupts.c に 青字部分を追加します。
①所要の変数を定義します。
short int angleValue = 0;
extern short int sinValue[360]; //sinテーブル値
extern DRV_HANDLE spi_Handle;
DRV_SPI_TRANSFER_HANDLE transferHandle; //Handle which is returned
by transfer add function.
//実際での使用: 排他制御(Semaphore、Mutex)の実行に於いてなど
②DAコンバータ MCP4922のCSを LOW("0")にセットします。
LATFbits.LATF2 = 0; //MCP4922 CS = 0
③SPIモジュールに所要の16ビット信号を書き込んで、書き込みが完了するまで待ちます。
更にMCP4922での処理が完了するまで待ちます。
PLIB_SPI_BufferWrite16bit(SPI_ID_4,(short int)(sinValue[angleValue]
| 0b0001000000000000)); //送信データ送信
// SPI4BUF = (short int)(sinValue[angleValue] |
0b0001000000000000); //送信データ送信
//MP4922 制御コマンド
//VoutAにゲイン2で出力
//MCP4922への書き込みコマンド
//bit15(書き込みレジスタ選択) 1:VoutB 0:VoutA
//bit14(予備)
//bit13(出力ゲイン選択) 1:1倍 0:2倍
//bit12(出力オフ制御) 1:出力ON 0:出力OFF
//bit11-bit0 データ MSBから順次送信される
//★ SPI4のバッファーレジスタ SPI4BUFへの書き込み
//1. Harmony V3 ライブラリ関数でSPIバッファーに書き込み
DRV_SPI_WriteTransferAdd(spi_Handle, &temp, sizeof(temp), &transferHandle);
//事前実行必須: DRV_SPI_Open(DRV_SPI_INDEX_0, DRV_IO_INTENT_WRITE); at APP_Initialize()
in app.c
////2. プロジェクト内部関数でSPIバッファーに書き込み
// SPI4_Initialize();
// SPI4_Write(&temp,sizeof(temp)); //事前実行必須: SPI4_Initialize(); at
APP_Initialize() in app.c
//3. バッファレジスタ直接書き込み
// SPI4BUF = temp; //SPI4のバッファーレジスタ SPI4BUFに直接書き込み
delay_us(20); //MCP4922の処理待ち
④ 角度を1度インクリメントします。 1周期(360度)になったら0度に戻します。
angleValue++;
if(angleValue >= 360)angleValue = 0;
⑤ DAコンバータ MCP4922のCSを HIGH("1")にセットします。
LATFbits.LATF2 = 1; //MCP4922 CS = 1;
// IFS0bits.T1IF = 0; //タイマ1割り込みフラグクリア
以下、interrupts.c 全文