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割り込みで起動できるように
なっています。
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018
#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 */
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095 096 097 098 099 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427
/* * 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 }