概要
今回は、dsPIC33AKシリーズで大幅に強化された高速ADCの使い方をご紹介します。
dsPIC33AKシリーズのADCは、従来のdsPIC33Cシリーズの3.5MSPSから40MSPSへと超高速サンプリングが可能になりました。これにより、より高精度なデータ取得が実現します。また、サンプリング時間の選択や入力変換の順序に自由度が増し、各入力チャンネルにはADフィルターやADコンパレータが構成されています。これにより、さまざまな用途での利用が可能となり、大幅な性能向上が期待できます。
関連記事
| 記事 | リンク | |
| 第1回 | dsPIC33AKシリーズについて | dsPIC33Aシリーズに関して – ぴくおの電子工作的な何かWP (electricpico.com) |
| 第2回 | 開発ボード、コンフィグレーション設定、クロック設定について | dsPIC33AKシリーズ②開発ボード,コンフィグレーション設定,クロック設定について – ぴくおの電子工作的な何かWP (electricpico.com) |
| 第3回 | CPU性能について | dsPIC33AKシリーズ③CPU性能について – ぴくおの電子工作的な何かWP (electricpico.com) |
| 第4回 | FPU性能について | dsPIC33AKシリーズ④FPU性能について – ぴくおの電子工作的な何かWP (electricpico.com) |
| 第5回 | DSPについて | dsPIC33AKシリーズ⑤DSPについて – ぴくおの電子工作的な何かWP (electricpico.com) |
| 第6回 | タイマー1割り込みの使い方 | dsPIC33AKシリーズ⑥Timer1割り込みの使い方 – ぴくおの電子工作的な何かWP (electricpico.com) |
| 第7回 | PMUの使い方 | dsPIC33AKシリーズ⑦PMUの使い方 – ぴくおの電子工作的な何かWP (electricpico.com) |
| 第8回(本記事) | 高速ADCの使い方 |
開発環境
開発環境を以下に示します。
| 項目 | 値 | リンク |
| ベースボード | dsPIC33A CURIOSITY PLATFORM DEVELOPMENT BOARD | dsPIC33A Curiosity Platform Development Board User’s Guide (microchip.com) |
| CPUボード(EV02G02A) | dsPIC33AK128MC106 General Purpose Dual In-Line Module (DIM) | dsPIC33AK128MC106 General Purpose Dual In-Line Module (DIM) | Microchip Technology |
| 統合開発環境 | MPLAB X IDE v6.20 | MPLAB® X IDE | Microchip Technology |
| コンパイラ | MPLAB XC DSC v3.10 | MPLAB® XC DSC Compiler | Microchip Technology |

ADC ブロック図と特徴まとめ
概要欄でも紹介しましたが、dsPIC33AKシリーズのADCは従来のADCと比較し大幅な進化を遂げています。
まずアナログ入力はマルチプレクサとスイッチを介してADCコアのサンプル・アンド・ホールド(S&H)回路、変換コアに接続されています。
マルチプレクサは設定チャンネル情報(出力フォーマット、測定モード、入力番号)を使用してアナログ・サンプルを処理します。
変換が完了すると、結果は特定のチャンネルの結果バッファに保存され、デジタル・フィルタとデジタル・コンパレータが設定されていれば、それらに渡されます。
ADC は各設定チャンネルにそれ自身のトリガー・ソースを指定する機能を提供します。この機能により、ADC は独立した時間ベースで動作する PWM ジェネレータに関連するアナログ入力をサンプリングして変換することができます。

- 12ビット分解能
- 最大40Msps変換
- 最大22アナログ入力ピン
- 20設定チャンネル 各チャンネル
- ディスクリート構成をサポート
- 任意のアナログ入力(I/Oピンまたは内部信号)に割り当て可能
- 異なるサンプリング時間に設定可能
- シングルエンドまたは差動として設定可能
- 変換結果を符号なしまたは符号ありでフォーマット可能
- 変換結果は左揃え可能(分数フォーマット)
- 独立した32ビット変換結果レジスタ
- 全チャンネルで4つのサンプリングモードをサポート:
- 複数サンプルのオーバーサンプリング
- 複数サンプルの積分
- ウィンドウ(ゲート信号がアクティブの時、複数サンプルが累積される)
- 単一変換
- 全チャンネルにデジタル・コンパレータがあり、変換結果が以下の場合、以上の場合、または範囲内、範囲外の場合を検出します。
設定可能なスレッショルドの範囲内または範囲外を検出します。 - チャンネル17、18、19はフィルタに使用可能な2番目の結果アキュムレータを持っています。
実装 - CPUスリープおよびアイドル・モード時に動作可能
- バンドギャップリファレンスおよび温度センサーダイオード入力
ADC変換モード
ADCの各チャンネルは以下の4つの変換モードを有しています。
AD1CHxCONbits.Mode = 0 : シングル変換モード
シンプルなシングル変換モード。
AD1CHxCONbits.TRIG1SRC で設定された入力がトリガされると、変換が開始される。
AD1CHxCONbits.Mode = 1:ウィンドウゲートモード
このモードでは、TRG1SRC[4:0] ビットで選択された信号がアクティブなレベルのときにサンプルが蓄積されます。すべての変換は TRG2SRC[4:0] トリガーによって開始されます。変換の回数は CNTx[15:0] ビット(ADnCNTx[15:0])によって制限されます。
AD1CHxCONbits.Mode = 2:積分マルチサンプルモード
最初の変換は TRG1SRC[4:0] トリガーによって開始され、他のすべての変換は TRG2SRC[4:0] トリガーによって実行されます。変換の回数は CNTx[15:0] ビット(ADnCNTx[15:0])によって制限されます。
AD1CHxCONbits.Mode = 2:オーバーサンプリングモード
最初の変換は TRG1SRC[4:0] トリガーによって開始され、他のすべての変換は TRG2SRC[4:0] トリガーによって実行されます。ACCNUM[1:0] で指定された4×(13bit)、16×(14bit)、64×(15bit)、256×(16bit)のオーバーサンプリング結果が得られます。
2次CICフィルタモード
チャンネル17,18,19は2次CICフィルタモードを有しています。CICの一部の操作(微分機能)は、図15-3に示されているように、アプリケーションソフトウェアによって実行する必要があります。

ADC動作確認①シングル変換
ソースコード
インクルードファイル
コンフィグレーションファイル、クロック設定ファイルは以下のファイルをインクルードしてください。
■コンフィグレーションファイル (config.h)
■クロック設定ソースファイル(Clock_Driver.c)
■クロックヘッダーファイル(clock_driver.h)
ソースコード全体
ADの初期設定も従来に比べ非常にシンプルです。
シンプルですが非常に高機能になりました。
#include <stdio.h>
#include <stdlib.h>
#include <xc.h>
#include "config.h"
#include "clock_driver.h"
#include <dsp.h>
#define ADC_RESULT_NUM 16
#define ADC_CH 20
uint32_t u4g_ADC1CH0Data[ADC_RESULT_NUM];
uint32_t u4g_ADC1Head[ADC_CH];
int main()
{
/*----------------------------------------------------------------------------*/
/*初期化*/
/*----------------------------------------------------------------------------*/
vdg_Clock_Set_Register();
ANSELAbits.ANSELA7 = 1u; //PortA7をアナログ入力に設定
AD1CH0CONbits.TRG1SRC = 1u; //AD変換開始はソフトウェアによる
AD1CH0CONbits.PINSEL = 6u; //AD1CH0+入力はAD1AN6
AD1CON = 0x00000000U;
AD1CONbits.ON = 1U; //AD1モジュールON
while(AD1CONbits.ADRDY == 0U)
{
;
}
AD1SWTRGbits.CH0TRG = 1U; //ソフトウェアトリガ発生
/*----------------------------------------------------------------------------*/
/*メインルーチン*/
/*----------------------------------------------------------------------------*/
while(1)
{
if (AD1STATbits.CH0RDY == 1U)
{
u4g_ADC1CH0Data[u4g_ADC1Head[0]] = AD1CH0DATA;
u4g_ADC1Head[0] ++;
if (u4g_ADC1Head[0] >= ADC_RESULT_NUM)
{
u4g_ADC1Head[0] = 0U;
}
AD1SWTRGbits.CH0TRG = 1U;
}
}
}
結果
配列にポテンションの値が格納されている事が確認できます。

ADC動作確認②積分モード
ソースコード
積分モードでは、最初にTRG1SRCがトリガーとなってAD変換が行われます。その後、TRG2SRCのイベントが発生するたびにAD変換が実行され、その結果が積算されます。そして、AD1CH0CNTのカウントに達した時点でAD変換が完了します。
#include <stdio.h>
#include <stdlib.h>
#include <xc.h>
#include "config.h"
#include "clcok_driver.h"
#include <dsp.h>
#define ADC_RESULT_NUM 16
#define ADC_CH 20
uint32_t u4g_ADC1CH0Data[ADC_RESULT_NUM];
uint32_t u4g_ADC1Head[ADC_CH];
int main()
{
/*----------------------------------------------------------------------------*/
/*初期化*/
/*----------------------------------------------------------------------------*/
vdg_Clock_Set_Register();
ANSELAbits.ANSELA7 = 1U; //PortA7をアナログ入力に設定
AD1CH0CONbits.TRG1SRC = 1u; //AD変換開始はソフトウェアによる
AD1CH0CONbits.TRG2SRC = 2u; //次回以降のAD変換は即時再トリガー
AD1CH0CONbits.PINSEL = 6u; //AD1CH0+入力はAD1AN6
AD1CH0CONbits.MODE = 2u;
AD1CH0CNT = 100u; //変換回数は100回
AD1CON = 0x00000000U;
AD1CONbits.ON = 1U;
while(AD1CONbits.ADRDY == 0U)
{
;
}
AD1SWTRGbits.CH0TRG = 1U;
/*----------------------------------------------------------------------------*/
/*メインルーチン*/
/*----------------------------------------------------------------------------*/
while(1)
{
if (AD1STATbits.CH0RDY == 1U)
{
u4g_ADC1CH0Data[u4g_ADC1Head[0]] = AD1CH0DATA;
u4g_ADC1Head[0] ++;
if (u4g_ADC1Head[0] >= ADC_RESULT_NUM)
{
u4g_ADC1Head[0] = 0U;
}
AD1SWTRGbits.CH0TRG = 1U;
}
}
}
結果
配列には、ポテンショメータの値が100回分積算された結果が格納されていることが確認できます。

ADC動作確認③オーバーサンプリングモード
ソースコード
オーバーサンプリングモードでは、最初にTRG1SRCがトリガーとなってAD変換が行われます。その後、TRG2SRCのイベントが発生するたびにAD変換が実行され、ACCNUMの設定値によってオーバサンプルされます。
#include <stdio.h>
#include <stdlib.h>
#include <xc.h>
#include "config.h"
#include "clcok_driver.h"
#include <dsp.h>
#define ADC_RESULT_NUM 16
#define ADC_CH 20
#define ADC_RESULT_NUM 16
#define ADC_CH 20
uint32_t u4g_ADC1CH0Data[ADC_RESULT_NUM];
uint32_t u4g_ADC1Head[ADC_CH];
int main()
{
/*----------------------------------------------------------------------------*/
/*初期化*/
/*----------------------------------------------------------------------------*/
vdg_Clock_Set_Register();
ANSELAbits.ANSELA7 = 1U; //PortA7をアナログ入力に設定
AD1CH0CONbits.TRG1SRC = 1u; //AD変換開始はソフトウェアによる
AD1CH0CONbits.TRG2SRC = 2u; //次回以降のAD変換は即時再トリガー
AD1CH0CONbits.PINSEL = 6u; //AD1CH0+入力はAD1AN6
AD1CH0CONbits.MODE = 3u; //変換モードは「オーバサンプリング」
AD1CH0CONbits.ACCNUM = 3u; //256×オーバーサンプリング
AD1CON = 0x00000000U;
AD1CONbits.ON = 1U;
while(AD1CONbits.ADRDY == 0U)
{
;
}
AD1SWTRGbits.CH0TRG = 1U;
/*----------------------------------------------------------------------------*/
/*メインルーチン*/
/*----------------------------------------------------------------------------*/
while(1)
{
if (AD1STATbits.CH0RDY == 1U)
{
u4g_ADC1CH0Data[u4g_ADC1Head[0]] = AD1CH0DATA;
u4g_ADC1Head[0] ++;
if (u4g_ADC1Head[0] >= ADC_RESULT_NUM)
{
u4g_ADC1Head[0] = 0U;
}
AD1SWTRGbits.CH0TRG = 1U;
}
}
}
結果
配列には、ポテンショメータの値が256倍オーバサンプリングされた16bitの結果が格納されていることが確認できます。

記事についての注意点
本記事は慎重に内容を検討し正確さに努めておりますが、もし内容に誤りがあったとしても、この記事を参考にして生じた損害等については一切の責任を負いません。

コメント