UMEHOSHI ITA TOP PAGE COMPUTER SHIEN LAB
マイクロコントローラ (PIC32MX270F256B-50I/SP)のADCは10 ビット で16個アナログ入力があります。(参考:61104F_JP.pdf)
このの使い方はいくつかありますが、
次のようにAN0とAN1の2つのアナログ入力を、それぞれMUX A およびMUX B の入力に設定し、
マルチプレクサでADCを交互に使うアナログ入力を変換する処理を組み込んでいます。

サンプリングしたワードは、左赤マルで示したADC1BUF0〜ADC1BUFFのレジスタに
記憶されます。(16 ビット符号なし整数の0〜1024を記憶させています。)
この16個のレジスタを 2つの8ワードバッファ(ADC1BUF) に分割構成して(AD1CON2bits.BUFM = 1)にしています。
一方のADC1BUFにサンプリング中に、もう一方のADC1BUFから取り出して後述の「struct ADC_BUFF」内に記憶します。
AN0とAN1の2つの入力を交互にサンプリングする指定(AD1CON2bits.ALTS = 1)で行っています。
組み込まれるプログラムでは、AN0かAN1の一方を指定する場合も、
AN0とAN1の2つの入力を交互にサンプリングしており、USBの出力だけが一方だけ出力をしています。
この2回のアナログからデジタル変換のサンプリングが完了するたびにADC割り込みが
発生するような初期設定をset_adc_exe関数で行っています。
(これはAD1CON2のSMPI<3:0>に1の設定で、サンプル数が2回ごとに割り込みさせています。)
ADC割り込み(下記adc_umeFunc1_1関数)ではサンプリング結果は、ADC1BUFの分割した一方に記憶し、
もう一方から取り出して「struct ADC_BUFF」に蓄えます。
ハード的にADC1BUF0とADC1BUF1レジスタ(それぞれAN0とAN1)に記憶さるタイミングで、
割り込みソフトによりADC1BUF8とADC1BUF9レジスタの内容を「struct ADC_BUFF」に蓄えます。
ハード的にADC1BUF8とADC1BUF9レジスタ(それぞれAN0とAN1)に記憶さるタイミングで、
割り込みソフトによりADC1BUF0とADC1BUF1レジスタの内容を「struct ADC_BUFF」に蓄えます。
そしてTimer3割り込みでは、サンプリングより蓄えられた「struct ADC_BUFF」からUSBへ送出する処理を行っています。
(対象のチャンネルの「struct ADC_BUFF」から2ワードをUSBへ出力する処理です。)
このUSB出力はset_adc_modeでCN8のAN0や CN9のAN1の入力源の選択と USBへの出力モード(テキストかバイナリ)の設定に従て行われます。
このUSBから出力する一つブロック数のサイズはset_adc_exe関数による設定に従って行われます。
以下が、AN0とAN1の2つの入力をサンプリングイメージです。(赤のマークがADC割り込みタイミングです)
(61104D.pdfのPage 17-57 と17-56を参考にした図です。59ページコードなどを参考にしてます。)
これらのADCのタイミングはTimer3を指定しています。
(AD1CON1bits.SSRC = 0b010; でTimer3 の周期一致時にサンプリング終了/ 変換開始をトリガに使い、
AD1CON3bits.ADRC = 0で ADC変換クロック源を周辺モジュール用クロック(PBCLK:40MHz)から生成)にしています。
このTimer3 のPR3の設定で、サンプリング周期が決まります。
一つのサンプリング周期は、(PR3の設定数+1)*(1/40e6)と値となりますが、
AN0とAN1の2つサンプリング全体のサンプリング周期は、この値の2分の1となります。
例えば、8KHzのサンプリングレートが必要となる場合、16KHz(周期が2分の1)の設定をします。
このPR3の設定値は、(1/16e3)/(1/40e6)-1=2499になります。
PR3の最低値は100程度です。(これは400KHz程度のサンプリングレートを意味します。)
下記で示す組み込みのADCとTimer3の割り込み関数を別途に作って作り変えれば、
もっと小さな(大きなサンプリングレート)のPR3も可能でしょう。
Timer3のイメージを下記に示します。
(参考:60001105G_JP.pdf)

ここで示すソース内で、主要関数の概要を以下に示します。
| 関数名 | 内容 |
|---|---|
| void init_adc() | ADCの初期化デフォルト関数です。 |
| void init_timer_3() | Timer3の初期化デフォルト関数です。TypeBの各種設定をしています。
T3CONのTGATE=0、
TCKPS=0b000 // [1:1]プリスケール値、
T32=0 // 16bitカウンタ指定、
TCS=0 // 周辺モジュールバス クロック(PBCLK) などの設定 |
| int set_adc_mode (int channel_bit, int text_mode_flag) |
引数channel_bitで、AN0のサンプリングを得るUSBの出力指定が1、AN1を得るUSBの出力指定が2、
AN0とAN1の2つをサンプリングを得るUSBの出力指定が3です。 |
| int set_adc_exe (int block_size, int loop_flag) |
ADCのの使い方を設定する関数 |
| void adc_umeFunc1_1(struct ADC_BUFF *p_buff) | ADCの割り込み処理 |
| void adc_usb_out(struct ADC_BUFF *p_buff) | Timer3の割り込み処理 |
struct ADC_CTRL {
uint32_t counter_ADC;//USB出力数のカウント
uint32_t count_end_ADC;//上記カウント目標値(block_size_ADCより設定)
int loop_flag_ADC;// ループサンプリングで1
int block_size_ADC;//サンプリングブロック数(1ブロックがADC_BUFF_SIZE)
int set_sequence_flag;
int out_channel_bits; // 1:AN0 or 2:AN1 or 3:(AN0,AN1)
void (*adc_out_usb)(uint32_t); // ADC USB output function
};
#define ADC_BUFF_SIZE 1024
#define ADC_OUT_NONE 2 // index_adc_out_blockの出力情報なしの定数
struct ADC_BUFF {
uint16_t adc_buffer0[2][ADC_BUFF_SIZE]; //AN0(CN8)
uint16_t adc_buffer1[2][ADC_BUFF_SIZE]; //AN1(CN9)
int index_adc_block_sample; //録音中の添え字 0 or 1
int index_adc_sample; // 録音位置
int index_adc_out_block;// USB出力中の添え字 0 or 1 で、出力情報無し時は2がset
int index_adc_out_pos; // USBの出力対象の添え字
int adc_buff_data_numb;// 実際のusbで送信するする際のワードサイズ目標値
struct ADC_CTRL *p_ctrl;
};
そして、my_adc.cで次の記憶域を用意して管理しています。
struct ADC_BUFF adc_buff = {
{0},{0},
0,
0,
2,
0,
ADC_BUFF_SIZE, // adc_buff_data_numb
& adc_ctrl
};
struct ADC_BUFF *p_buff = & adc_buff;
使われている構造は、逐次比較型(SAR) アナログ/ デジタルコンバータ (ADC)と呼ばれるもので、
アナログサンプリングは「アクイジション」と「変換」の 2 つのステップ により構成されます。
この変換が終わったタイミングで、ADCの割り込みが行われています。
ADCの割り込み処理は、「_HANDLES[_IDX_ADC_1_FUNC]」で、変更可能になっており、
初期値はmy_sys.cで、「adc_umeFunc1_1」関数が登録されています。
この割り込みの「adc_umeFunc1_1」関数では、上記ADC_BUFF構想体の
メンバadc_buffer0,adc_buffer1の配列に格納する処理が行われています。
各配列は、2byte要素が1024並ぶ領域が2つある2次配列で、
割り込みで一方の1024個並ぶ要素へ1要素ずつ格納する処理が行われ、
同時にもう一方の1024個から取り出して、USBに送信する処理が
adc_usb_out(struct ADC_BUFF *p_buff)関数です。
この、デフォルトでTimer3割り込みで起動できるように
なっています。
#ifndef _MY_ADC_H /* Guard against multiple inclusion */ #define _MY_ADC_H #include "my_beep.h" struct ADC_BUFF * get_ptr_adc_buff(); extern struct ADC_BUFF *p_buff; void encode_adc_buff( struct ADC_BUFF *p_buff ); int set_adc_exe(int block_count, int loop_flag); int set_adc_mode(int channel_bit, int text_mode_flag); void adc_usb_out(struct ADC_BUFF *p_buff); void adc_umeFunc1_1(); void init_timer_3(); void init_adc(); #define MY_ADC_ERR_OVERFLOW 0x0001 // ADC取得データの送信が間に合わなないエラー #endif /* _MY_ADC_H */
/*
* USB のADCに必要な処理
* (関連TIMER3の処理を含む)
*/
#include <xc.h>
#include <stdio.h>
#include <sys/attribs.h>//割込み関係の定義
#include <proc/p32mx270f256b.h>
#include "my_app.h"
#include "my_usb_cmd.h"
#include "my_adc.h"
#include "my_sys.h"
#include "common.h"
/*****************************************************
* ADC関連のグローバル変数と関数
****************************************************/
uint16_t my_adc_err = 0; // my_adc.c でのエラー情報
// 上記エラー情報への設定関数
int my_adc_set_err(uint16_t d) {
my_adc_err |= d;
}
/* ADC_CTRL構造体
* int block_size_ADC = 1;// これが、0ならストップシーケンス、0以外なら起動シーケンス
* ADC_BUFF_SIZE * block_count_ADC のサイズが1回のUSB出力のデータ数となる。
* この数を "ADC_START\r\n" の直後に16進で送出して、"\r\nを出してデータ出力を始める
* int set_sequence_flag = 1; //この構造体の設定する登録時に1、無いなら0
* int out_channel_bits = 0x03; //使用チャンネル(AN0,AN1)の指定
* int adc_buff_data_numb; // usbで送信する実際のワードサイズ
*/
struct ADC_CTRL adc_ctrl = {// defualt
0, // counter_ADC
ADC_BUFF_SIZE * 1, // count_end_ADC
1, // loop
1, // block_size_ADC
1, // set_sequence_flag
0x03, // out_channel_bits 使用チャンネル(AN0,AN1)の指定
send_16byte // ADCのUSB出力関数へのポインタ(send_16byte or send_hex_low)
};
struct ADC_CTRL *p_ctrl = &adc_ctrl;
/* 下記構造体(struct ADC_BUFF)のメンバのデータの概要
* ADCのサンプリング割込みで、index_block_sampleが指すバッファ内に記憶するが、
* 一杯になったら次の添え字に移動する。その時その添え字がindex_out_blockと同じあれば
* まだ送信されていないのでサンプリング不可として、割込みを停止する。
* (サンプリングが可能であれば、index_out_blockを更新する。)
* index_adc_block_sampleの添え字移動は、0→1、1→0の通り
* int index_adc_out_block;は 2 である時、出力対象が存在しない。
* int index_adc_out_pos; 0〜ADC_BUFF_SIZEで、 ADC_BUFF_SIZEは出力済み状態を意味する。
*/
struct ADC_BUFF adc_buff = {
{0},// uint16_t adc_buffer0[2][ADC_BUFF_SIZE]; //AN0(CN8)
{0},// uint16_t adc_buffer1[2][ADC_BUFF_SIZE]; //AN1(CN9)
0, // int index_adc_block_sample; //録音中の添え字 0 or 1
0, // int index_adc_sample; // 録音位置
ADC_OUT_NONE,// int index_adc_out_block;// USB出力中の添え字 0 or 1 or ADC_OUT_NONE
0, // int index_adc_out_pos; // USBの出力対象の添え字
ADC_BUFF_SIZE, // int adc_buff_data_numb;// 1ブロックで出力する実際のデータ数
& adc_ctrl
};
struct ADC_BUFF *p_buff = &adc_buff;
struct ADC_BUFF *get_ptr_adc_buff() {
return & adc_buff;
}
// 引数がadc_block_countが0の場合は、終了指示 loop_flagが1でループ
// Timer3が動作中の場合、loop_flag を0にすると、block_countは無視して終了シーケンス
// Timer3が動作中の場合、loop_flag を1であればblock_countの変更可能
// Timer3が動作していない場合中の場合、loop_flag を0にしてもblock_countで起動可能
// 既に、動作していれば、set_sequence_flag を1にする。
// 戻り値:set_sequence_flagの内容返す。(set_sequence_flagの設定前の値)
int set_adc_exe(int block_size, int loop_flag) {
int rtnval = p_ctrl->set_sequence_flag;
p_ctrl->block_size_ADC = block_size;
p_ctrl->loop_flag_ADC = loop_flag;
if (T3CONbits.ON == 0 && p_buff->index_adc_out_block == ADC_OUT_NONE) {
//現在割込みが止まっている。
p_buff->index_adc_block_sample = 0; //録音中の添え字 0 or 1
p_buff->index_adc_sample = 0; // 録音位置.
p_buff->index_adc_out_block = ADC_OUT_NONE; //USB送信中は、0か1になる。
p_buff->index_adc_out_pos = 0; // USBの出力対象の添え字.
p_ctrl->counter_ADC = 0;
if (block_size != 0) {
p_ctrl->count_end_ADC = ADC_BUFF_SIZE * p_ctrl->block_size_ADC; // 目標サンプル数
if (p_ctrl->out_channel_bits == 0x3) {
p_ctrl->count_end_ADC <<= 1; //AN0,AN1 の2つ分
}
AD1CON1 = 0x8046;
T3CONbits.ON = 1; // Timer3スタート
}
} else {// 既に動いている場合の指定
p_ctrl->set_sequence_flag = 1; //上記を設定
}
return rtnval;
}
// channel_bitの0x1がAN0のサンプリング指定、0x2がAN1のサンプリング指定、両方は0x3
// text_mode_flagが1で、ADCデータの出力をテキストモードに指定(バイナリなら0を指定)
int set_adc_mode(int channel_bit, int text_mode_flag) {
p_ctrl->out_channel_bits = channel_bit;
AD1CON2bits.SMPI = 0b0001; // 2つのADCサンプリング後にADC割り込みを発生させる指定。
// 全体のサンプリング周期は、「PR3で指定した1つのADCサンプリング時間×2」となる。
if (text_mode_flag != 0) {
p_ctrl->adc_out_usb = send_hex_low; // テキスト出力関数へのポインタ
} else {
p_ctrl->adc_out_usb = send_16byte; // バイナリー出力関数へのポインタ
}
IEC0CLR=_IEC0_T3IE_MASK;// // timer3の出力割り込み不許可★
}
// USBへ送信する直前で呼び出される送信データの加工処理用の置き換え元関数.
void encode_adc_buff(struct ADC_BUFF *p_buff) {
// パワーオン時に、handlers[_IDX_ENCODE_ADC_BUFF]に記憶される関数
// 後述のadc_usb_out関数より呼び出される何もしないダミー関数
}
/*
* ADC 割り込み処理 -----------------------------------------------------------
*/
void adc_umeFunc1_1(struct ADC_BUFF *p_buff) {
static int no_send_count = 0; // 送信できない場合のデクリメント
static uint16_t valAN0, valAN1;
int flag_stop = 0;//★ADCの割り込みを終了するタイミングで1
// 割り込み中で、下記バッファを必ず操作しなければならない。
// (そうしないと、割込みが永続(persistent)のため、連続発生の不具合が生じる。)
// バッファへの格納先を確認(ビットチェック格納先を判定)
int idx = (AD1CON2 & _AD1CON2_BUFS_MASK) != 0;
if (idx) {//1:ADC はバッファ0x8〜0xF に書き込み中(ユーザは0x0〜0x7 にアクセス可能)
valAN0 = ADC1BUF0; //AN0
valAN1 = ADC1BUF1; //AN1
} else { //0: ADC はバッファ0x0〜0x7 に書き込み中(ユーザは0x8〜0xF にアクセス可能)
valAN0 = ADC1BUF8; //AN0
valAN1 = ADC1BUF9; //AN1
}
if (p_buff->index_adc_sample >= ADC_BUFF_SIZE) {
if (p_buff->index_adc_out_block != ADC_OUT_NONE) {
IEC0SET=_IEC0_T3IE_MASK; // timer3の出力割り込み許可★
//(adc_buffer0 or 1のバッファを記憶し終わったタイミング)
if( PR3 < 500 ) {// 約80KHzを超えるサンプリングでは次の割り込みを不可
flag_stop = 1;
}//★
// エラーのサンプリング停止(メモリオーバー USB出力が間に合わない).
no_send_count--;
goto end_proc; // 下記のサンプリングをしない
}
// オルタネイト・バッファブが一杯なので、切り替える
p_buff->index_adc_sample = 0;
int next_index_block_sample = p_buff->index_adc_block_sample;
next_index_block_sample++;
if (next_index_block_sample == 2) {
next_index_block_sample = 0;
}
p_buff->index_adc_out_block = p_buff->index_adc_block_sample;
p_buff->index_adc_block_sample = next_index_block_sample;
if( flag_stop ){ // サンプルレートが高い場合、バッファを使い切ったら止める★
IFS0CLR = _IFS0_AD1IF_MASK; // Clear ADC interrupt flag
IEC0CLR = _IEC0_AD1IE_MASK; // ADC 割込み不許可
return;
}//★
}
if (no_send_count != 0) {// USB出力が間に合わないくて、出力されなかったデータ数?
valAN0 = valAN1 = no_send_count; //出力できなかった数を(負の数)セット
no_send_count = 0;
}
//valAN0 = valAN1 = cv;//デバック用データ設定.
p_buff->adc_buffer0[p_buff->index_adc_block_sample][p_buff->index_adc_sample] = valAN0;
p_buff->adc_buffer1[p_buff->index_adc_block_sample][p_buff->index_adc_sample] = valAN1;
p_buff->index_adc_sample++;
end_proc:
IFS0CLR = _IFS0_AD1IF_MASK; // Clear ADC interrupt flag
}
// =============================================================================
// ADCのUSB出力 (Timer3の割込み処理)
// p_buffが管理する選択チャンネルのバッファから1ワードをUSBへ出力する。
// 選択チャンネル(p_buff->p_ctrl->out_channel_bits)が1であればAN0、2でAN1、
// 3の場合はAN0とAN1の両方の1ワード(2ワード分)を出力する。
// 出力対象の1ワードは、p_buff->p_ctrl->out_channel_bitsが1のAN0であれば次の要素となる
// p_buff->adc_buffer0[p_buff->index_adc_out_block][p_buff-index_adc_out_pos]
// ここで、ADCの設定が終わったindex_adc_out_blockは0また1であるが、
// バッファ内容を全て送信し終わったタイミングで、ADC_OUT_NONEに設定される。
// つまり、p_buff->index_adc_out_blockが2である時、送信データがない状態と判断している。
void adc_usb_out(struct ADC_BUFF *p_buff) {
static bool flag_start_ADC = true;
static bool flag_end_ADC = false;
static int i, idx_block, i_pos;
static int16_t data;
static int tim3_skip_count=0;// timer3が早すぎる場合の送出調整用★
static int skip_timing =0;//★
skip_timing = PR3;
if( skip_timing < 100) { // 1つのサンプル周期が約400KHz以上?★
skip_timing = 100 - skip_timing;
tim3_skip_count++;
if(tim3_skip_count < skip_timing ) {
IFS0CLR = _IFS0_T3IF_MASK; // 次の割り込みを可能にする
return;
}
tim3_skip_count =0;
}//★
struct ADC_CTRL *p_ctrl = p_buff->p_ctrl;
if (p_buff->index_adc_out_block == ADC_OUT_NONE) {// USB送信するデータがない? .
IFS0CLR = _IFS0_T3IF_MASK; // Clear the timer interrupt status flag
return;
}
int size = get_capacity();
if (size < 50) {
IFS0CLR = _IFS0_T3IF_MASK; // Clear the timer interrupt status flag
return; //USB出力バッファに余裕がないので、次の呼び出しにする。
}
if (request_acc_outbuff(_ID_ACCESS_T3_TASK) == false) {
IFS0CLR = _IFS0_T3IF_MASK; // Clear the timer interrupt status flag
return; //USB出力権限取得失敗で、、次の呼び出しにする。
}
// ADC DATA 送出.============>USB
if (flag_start_ADC) {// ----------送出ブロック開始----------------
p_buff->adc_buff_data_numb = ADC_BUFF_SIZE;
((void (*)(struct ADC_BUFF*))_UME_ENCODE_ADC_BUFF)(p_buff);
if (p_ctrl->out_channel_bits == 0x3) { // AN0, AN1 両方の出力
send_string("\r\nADC_START\r\n");
if (p_ctrl->adc_out_usb == send_hex_low)send_char('T'); //TextMode
send_hex_low(p_ctrl->count_end_ADC); //送信データ数(X2))
} else if (p_ctrl->out_channel_bits == 0x1) {
send_string("\r\nADC_START0\r\n");
if (p_ctrl->adc_out_usb == send_hex_low)send_char('T'); //TextMode
send_hex_low(p_ctrl->count_end_ADC); //送信データ数
} else if (p_ctrl->out_channel_bits == 0x2) {
send_string("\r\nADC_START1\r\n");
if (p_ctrl->adc_out_usb == send_hex_low)send_char('T'); //TextMode
send_hex_low(p_ctrl->count_end_ADC); //送信データ数
}
send_string("\r\n");
usb_receiver_disable_flag = 1; //USB受信不可
flag_start_ADC = false; //開始処理を終えた〇
flag_end_ADC = false;
} else if (p_ctrl->counter_ADC >= p_ctrl->count_end_ADC) {
// ----------送出ブロック終了の処理------
if (!flag_end_ADC) {
flag_end_ADC = true;
flag_start_ADC = true;
send_string("ADC_END\r\n");
usb_receiver_disable_flag = 0; //USB受信不可解除
if (p_ctrl->set_sequence_flag) {// set_ADCの登録がある時
p_ctrl->set_sequence_flag = 0;
if (p_ctrl->block_size_ADC != 0) {// 継続データ指示がある ?
// 目標サンプル数 設定があればセット
p_ctrl->count_end_ADC = p_buff->adc_buff_data_numb * p_ctrl->block_size_ADC;
if (p_ctrl->out_channel_bits == 0x3) {
p_ctrl->count_end_ADC <<= 1; //AN0,AN2 の2倍
}
} else {
T3CONbits.ON = 0; // timer3停止
p_buff->index_adc_out_block = ADC_OUT_NONE;
}
}
if (!p_ctrl->loop_flag_ADC) {//ループしない?
T3CONbits.ON = 0; // timer3割込みオフ.
p_ctrl->block_size_ADC = 0;
p_buff->index_adc_out_block = ADC_OUT_NONE;
}
p_ctrl->counter_ADC = 0;
}
} else {// ------------- ADC データブロック送出中 -------------------------
for (i = 0; i < 2; i++) {// ADCの値の1ワードを2つ分送出する。
idx_block = p_buff->index_adc_out_block;
i_pos = p_buff->index_adc_out_pos;
if ((p_ctrl->out_channel_bits & 1) != 0) {
data = p_buff->adc_buffer0[idx_block][i_pos]; //出力対象
if (data < 0) my_adc_set_err(MY_ADC_ERR_OVERFLOW);
p_ctrl->adc_out_usb(data);
p_ctrl->counter_ADC++;
}
if ((p_ctrl->out_channel_bits & 2) != 0) {
data = p_buff->adc_buffer1[idx_block][i_pos]; //出力対象
if (data < 0) my_adc_set_err(MY_ADC_ERR_OVERFLOW);
p_ctrl->adc_out_usb(data);
p_ctrl->counter_ADC++;
}
++p_buff->index_adc_out_pos;
if (p_ctrl->counter_ADC % 16 == 0 && p_ctrl->adc_out_usb == send_hex_low) {
// TEXT MODE 出力の場合だけ出力(バイナリ時は出力しない)
send_string("\r\n");
}
if (p_buff->index_adc_out_pos >= p_buff->adc_buff_data_numb) {
p_buff->index_adc_out_pos = 0;
p_buff->index_adc_out_block = ADC_OUT_NONE; // CHUNKブロックのUSB出力終了.
}
}
}
release_acc_outbuff(_ID_ACCESS_T3_TASK);
IFS0CLR = _IFS0_T3IF_MASK; // Clear the timer interrupt status flag
}
// Timer3 の初期化(ADCのサンプリング周期を作る)------------------------------------
void init_timer_3() {
T3CON = 0x00000000; //typeB,16bit, [1:1]プリスケール
T3CONbits.ON = 0; // typeBでON(b15)
T3CONbits.SIDL = 0; // デバイスがアイドルモードに移行しても動作を継続する(b13)
T3CONbits.TGATE = 0; // ゲート時間積算を無効にする(b7)
T3CONbits.TCKPS = 0; // タイマ入力クロック 0〜3プリスケール値(b6-4)
T3CONbits.TCS = 0; //内部の周辺モジュール用クロック(b1)
// 以上より、タイマーのカウントアップ周期は、次のように算出される。
// 「TCS = 0」で、周辺モジュールバス クロック(PBCLK) は40MHzになっている。
// よってカウント周期は 1/40e6=2.5e-08=250u秒
//__asm__("nop");
TMR3 = 0x00000000; //16bitタイマの設定値(レジスタがカウントアップ)
PR3 = 0x1; //16bit周期レジスタビット設定(タイマーが働く最小値)
PR3 = 0x0000FFFF; //16bit周期レジスタビット設定(16タイマーの最大値)
PR3 = 40000-1; //16bit周期レジスタビット設定( 割り込み周期が1m秒)
PR3 = 907-1; //44,100Hzが音楽業界の標準で、この周期に近い割り込み周期(約0.23ミリ秒)
// 1/(907 * (1/40e6))=44101.43329658214Hzの周波数になり、少しずれる。
// 2つチャンネルなので、上記設定の実質的サンプリング周波数は÷2=約22050.7Hz
PR3 = 1250/2-1;//32KHzのサンプリング周期(割り込み周期は2チェンネルで16Kの周期)
PR3 = 1666/2-1;//24KHzのサンプリング周期(割り込み周期は2チェンネルで12Kの周期)
PR3 = 2500/2-1;//16KHzのサンプリング周期(割り込み周期は2チェンネルで8Kの周期)
IPC3SET = 6 << _IPC3_T3IP_POSITION; // Set priority level = 6
IPC3SET = 2 << _IPC3_T3IS_POSITION; // Set sub-priority level = 2
IFS0CLR = _IFS0_T3IF_MASK; // Clear the timer interrupt status flag
IEC0SET = _IEC0_T3IE_MASK; // Timer3 Enable(割込み許可)
//T3CONSET = _T3CON_TON_MASK; // timer3 Start
//T3CON = 0b1000000000000000; // timer3 機能ON
}
// ADCの初期化デフォルト関数------------------------------------------------------
void init_adc() {
// ----- ADC 関連の初期設定 ここから[61104F_JP.pdf P17-4]
TRISASET = 0x00000003; // RA0、RA1のポートを入力用に設定
AD1CON1 = 0; // スタート、ストップ制御関連制御レジスタ
AD1CON2 = 0; // 入力スキャン指定、出力バッファ指定などシーケンス指定制御レジスタ
AD1CON3 = 0; // クロック関連指定制御レジスタ
AD1CHS = 0; // アナログ入力のマルチプレクサの指定
//AD1PCFG = 0; 当チップではこのポートコンフィグレーションレジスタは存在しない。
AD1CSSL = 0; // 入力スキャン選択レジスタ
// AD1CHS設定-----------------------------------
AD1CHSbits.CH0NB = 0; // b31 CH0NB:0 MUX B 負極性入力選択ビット=VR- を選択する
// b30-b28 未実装 :「0」として読み出し
// b27-b24 CH0SB<3:0>: 0b0001 MUX B 正極性入力選択ビット=AN1 を選択する
// b23 CH0NA:0 MUX A 負極性入力選択ビット=VR- を選択する
// b22-b20 未実装 :「0」として読み出し
// b19-b16 CH0SA<3:0>: 0b0000 MUX A 負極性入力選択ビット=AN0 を選択する
// b15-b0 未実装 :「0」として読み出し
// CH0NB XXX CH0SB CH0NA XXX CH0SA XXXXXXXX XXXXXXXX
// 0 000 0001 0 000 0000 00000000 00000000
AD1CHS = 0x01000000; // MUX AにはAN0,MUX BにAN1 の入力を接続
//AD1CON3設定--ADC 制御レジスタ 3 クロック関連指定制御レジスタ-----------------
AD1CON3 = 0x0; // b31-b16 未実装 :「0」として読み出し
AD1CON3bits.ADRC = 0; // b15 ADC変換クロック源の選択ビット
// 1: FRCクロック使用、0:周辺モジュール用クロック(PBCLK:40MHz)から生成
// b14-b13 未実装 :「0」として読み出し
AD1CON3bits.SAMC = 0b00010; // b12-b8 自動サンプリング時間ビット= 2TAD
//上記はアナログ入力ピンをサンプル/ホールドアンプ(SHA)に接続するアクイジション時間
AD1CON3bits.ADCS = 0b00000011; /// b7-b0 ADC 変換クロック選択ビット
// ADCの変換時間(8bit) = TPB * 2 * (ADCS<7:0> + 1) = 512 * TPB = TAD
// XXXXXXXX XXXXXXXX ADRC XX SAMC ADCS
// 00000000 00000000 0 00 00010 00111111
AD1CON3 = 0x0000023F;
// AD1CON2 (ADC 制御レジスタ 2)設定 --------------------
// [61104F_JP.pdf P17-4]「17.4.11.2 2 つの入力マルチプレクサを交互に使う」
AD1CON2 = 0x0;
AD1CON2bits.VCFG = 0; //参照電圧にAVDDとAVSSを使う(b15-b13)
AD1CON2bits.OFFCAL = 0; //オフセット校正モードを無効(b12)
AD1CON2bits.CSCNA = 0; //入力をスキャンしない(b10)
AD1CON2bits.BUFS = 0; //バッファ書き込みステータスビット(b7)
// 1 = ADC はバッファ0x8〜0xF に書き込み中( ユーザは0x0〜0x7 にアクセス可能)
// 0 = ADC はバッファ0x0〜0x7 に書き込み中( ユーザは0x8〜0xF にアクセス可能)
AD1CON2bits.SMPI = 0b0001; //割り込みシーケンス選択ビット(b5-b2)
// 上記は、2 回のサンプリング/ 変換が完了するたびに割り込む
AD1CON2bits.BUFM = 1; //ADCデータ格納バッファモード選択ビット(b1))
//上記 1: 2つの8ワードバッファ(ADC1BUF) を分割構成
AD1CON2bits.ALTS = 1; //MUXAおよびMUXBを交互に使う指定(b0))
// VCFG OFFCA X CSCNA XX BUFS X SMPI BUFM ALTS
// 000 0 0 0 00 0 0 0001 1 1
AD1CON2 = 0x0007;
// AD1CON1設定 ------------------------------------------
AD1CON1 = 0; // b31-b16 未実装
AD1CON1bits.ON = 1; //ADC モジュールを有効にする(b15)
AD1CON1bits.SIDL = 0; //アイドル中もモジュールの動作を継続する(b13)
AD1CON1bits.FORM = 0b000; //16 ビット符号なし整数の指定(b10-b8)
AD1CON1bits.SSRC = 0b010; //変換トリガ源選択ビット(b7-b5)
// 上記3ビット指定:Timer3 の周期一致時にサンプリング終了/ 変換開始をトリガする
AD1CON1bits.CLRASAM = 0; //割り込み時変換停止ビット(bit4)
// (0 = 次の変換シーケンスがバッファの内容を上書き)
// (1 = 最初のADC 割り込みが発生した時点で変換を停止する)
// SSRCがTimer3の時、CLRASAMの1を行ってもTimer3によるADC割り込みは停止できない。
AD1CON1bits.ASAM = 1; //ADC サンプリング自動開始ビット(b2)
//これをセットしないと、割込みが発生しなかった。
// 変換完了後即座にサンプリングを開始する(SAMP ビットを自動的にセットする)
AD1CON1bits.SAMP = 1; //ADC サンプリングイネーブルビット(b1)
AD1CON1bits.DONE; //変換が完了すると1になる。(b0)
// ON X SIDL XX FORM SSRC CLRASAM X ASAM SAMP DONE
// 1 0 0 00 000 010 0 0 1 1 0
AD1CON1 = 0x0046;
IPC5SET = 7 << _IPC5_AD1IP_POSITION; // Set priority level = 7
IPC5SET = 1 << _IPC5_AD1IS_POSITION; // Set sub-priority level = 1
IFS0CLR = _IFS0_AD1IF_MASK; // Clear the ADC interrupt status flag
IEC0SET = _IEC0_AD1IE_MASK; // ADC Enable(割込み許可)
AD1CON1bits.ADON = 1; // Begin Sampling
}