UMEHOSHI ITA TOP PAGE    COMPUTER SHIEN LAB

UMEHOSHI IT (my_adc.c と my_adc.h)

マイクロコントローラ (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の初期化デフォルト関数です。
ここでMUX AN0に入力 、 MUX B にAN1に入力して、MUX A および MUX B 入力選択を交互に使う設定にしている。
Timer3 の周期一致時にサンプリング終了/ 変換開始をトリガする設定にして、 ADCモジュールを有効にしています。
つまり、Timer3 が割り込みを始めると、ADCの交互サンプリングが始まり、 AN0のAN1の2つ結果をADC1BUF~に記憶して次のサンプリングが始まるタイミングで ADC割り込み処理(デフォルトはadc_umeFunc1_1関数)が呼び出されます。
(AD1CON1 = 0x8046;//ON=1, SSRC=010, ASAM=1, SAMP=1)
またTimer3 のT3CONbits.ON制御で、ADコンバータ処理のON/OFFを制御しています。

void init_timer_3()

Timer3の初期化デフォルト関数です。TypeBの各種設定をしています。 T3CONのTGATE=0、 TCKPS=0b000 // [1:1]プリスケール値、 T32=0 // 16bitカウンタ指定、 TCS=0 // 周辺モジュールバス クロック(PBCLK) などの設定
PR3 = 5000/2-1で8KHzのサンプリング周期にしている。 別途に、 PR3 = 2500/2-1; で16KHz、PR3 = 1250/2-1; で32KHz、 PR3 = 1666/2-1; で24KHzに変更でます。
PR3の最低値は100程度です。サンプリング周期は、((1/サンプリング周波数)/(1/40e6)-1)/2で算出できます。

int set_adc_mode
(int channel_bit,
int text_mode_flag)

引数channel_bitで、AN0のサンプリングを得るUSBの出力指定が1、AN1を得るUSBの出力指定が2、 AN0とAN1の2つをサンプリングを得るUSBの出力指定が3です。
(channel_bitに1または2の一方だけのUSBの出力指定でも、交互サンプリングにより両方の入力がADC変換対象になっています)
またtext_mode_flagが1でADCデータの出力をテキストモードに指定します。(0であればバイナリ指定を意味します)

int set_adc_exe
(int block_size,
int loop_flag)

ADCのの使い方を設定する関数
block_sizeで、1回のUSBで送出するデータサイズを1から36の範囲で指定します。 この指定値は、ADC_BUFF_SIZEの1024ワードを1と数えた値を単位です。
(2であれば、ADC_STARTとADC_ENDに挟まれた送出データ数が2048ワードとなる)
そして loop_flagが1であれば、このブロックを連続的に生成する指定を意味し、0であればblock_sizeでサンプリングを終えます。
block_sizeに3以上を指定することやloop_flagに1を指定する場合は、PR3に4999程度以上の設定が必要でしょう。
(PR3の設定値の最低値は、接続USBの性能、USBに出力するチャンネル数などに依存します)
なお、PR3の設定値が500未満の時は、block_sizeに3以上やloop_flagに1しても無効となり、block_sizeが2のサンプリングが終了するまで USBの出力が行われません。(この時はサンプリングが終了した時点で、timer3の割り込みが始まりUSBの出力が始まります)

void adc_umeFunc1_1(struct ADC_BUFF *p_buff)

ADCの割り込み処理
サンプリング結果が記憶される「ADC1BUF0とADC1BUF1」または、「ADC1BUF8とADC1BUF9」を、 p_buff->buffer0とp_buff->buffer1の配列要素に記憶しています。

void adc_usb_out(struct ADC_BUFF *p_buff)

Timer3の割り込み処理
p_buff->buffer0とp_buff->buffer1の配列をUSBに送出する。


これを制御する構造体が、common.hで次のように定義しています。
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割り込みで起動できるように なっています。

my_adc.hのソース

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 */

my_adc.cのソース

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    
}