/************************************************************************ * High_Speed_Oscillo_Test * PIC24F GCシリーズに内蔵の高速ADCを使っての、高速オシロの実験 * * MPU:PIC24FJ64GC006 * 2.4インチQVGA液晶モジュール(aitendo): UL024TF使用 * * デバッグ年月日: 2015/12/16 N.Ishii * ================================================================== * /// 以下は、後閑氏のオリジナル・コメント(これを基にスタンドアロン化) * ワイアレスオシロスコープ * PIC24FJ64GC006 の10Mspsのパイプライン型ADCの使用例 *  Timer2でA/D変換し、DMAでバッファに格納 * 可能な変換速度は 4Mspsが限界 @Tad=8MHz *  コマンドで下記実行 *   T :変換開始 2000回のサンプリングを送信する * *************************************************************************/ #include #include "colorlcd_libdsPICVH.h" //#include //#include "imagedata.h" /* コンフィギュレーションの設定 */ // CONFIG4 #pragma config DSWDTPS = DSWDTPS1F // Deep Sleep Watchdog Timer Postscale Select bits (1:68719476736 (25.7 Days)) #pragma config DSWDTOSC = LPRC // DSWDT Reference Clock Select (DSWDT uses LPRC as reference clock) #pragma config DSBOREN = OFF // Deep Sleep BOR Enable bit (DSBOR Disabled) #pragma config DSWDTEN = OFF // Deep Sleep Watchdog Timer Enable (DSWDT Disabled) #pragma config DSSWEN = OFF // DSEN Bit Enable (Deep Sleep operation is always disabled) #pragma config RTCBAT = OFF // RTC Battery Operation Enable (RTC operation is discontinued in VBAT) #pragma config PLLDIV = DIV2 // PLL Input Prescaler Select bits (Oscillator divided by 2 (8 MHz input)) #pragma config I2C2SEL = PRI // Alternate I2C2 Location Select bit (I2C2 is multiplexed to SDA2/RA3 and SCL2/RA2 ) #pragma config IOL1WAY = OFF // PPS IOLOCK Set Only Once Enable bit (The IOLOCK bit can be set and cleared using the unlock sequence) // CONFIG3 #pragma config WPFP = WPFP127 // Write Protection Flash Page Segment Boundary (Page 127 (0x1FC00)) #pragma config SOSCSEL = OFF // SOSC Selection bits (Digital (SCLKI) mode) #pragma config WDTWIN = PS25_0 // Window Mode Watchdog Timer Window Width Select (Watch Dog Timer Window Width is 25 percent) #pragma config BOREN = OFF // Brown-out Reset Enable (Brown-out Reset Disabled) #pragma config WPDIS = WPDIS // Segment Write Protection Disable (Disabled) #pragma config WPCFG = WPCFGDIS // Write Protect Configuration Page Select (Disabled) #pragma config WPEND = WPENDMEM // Segment Write Protection End Page Select (Write Protect from WPFP to the last page of memory) // CONFIG2 #pragma config POSCMD = EC // Primary Oscillator Select (External-Clock Mode Enabled) #pragma config WDTCLK = LPRC // WDT Clock Source Select bits (WDT uses LPRC) //#pragma config OSCIOFCN = OFF // OSCO Pin Configuration (OSCO/CLKO/RC15 functions as CLKO (FOSC/2)) #pragma config FCKSM = CSDCMD // Clock Switching and Fail-Safe Clock Monitor Configuration bits (Clock switching and Fail-Safe Clock Monitor are disabled) #pragma config FNOSC = PRIPLL // Initial Oscillator Select (Primary Oscillator with PLL module (XTPLL,HSPLL, ECPLL)) #pragma config ALTADREF = AVREF_RA // External 12-Bit A/D Reference Location Select bit (AVREF+/AVREF- are mapped to RA9/RA10) #pragma config ALTCVREF = CVREF_RA // External Comparator Reference Location Select bit (CVREF+/CVREF- are mapped to RA9/RA10) #pragma config WDTCMX = WDTCLK // WDT Clock Source Select bits (WDT clock source is determined by the WDTCLK Configuration bits) #pragma config IESO = OFF // Internal External Switchover (Disabled) // CONFIG1 #pragma config WDTPS = PS32768 // Watchdog Timer Postscaler Select (1:32,768) #pragma config FWPSA = PR128 // WDT Prescaler Ratio Select (1:128) #pragma config WINDIS = OFF // Windowed WDT Disable (Standard Watchdog Timer) #pragma config FWDTEN = WDT_DIS // Watchdog Timer Enable (WDT disabled in hardware; SWDTEN bit disabled) #pragma config ICS = PGx2 // Emulator Pin Placement Select bits (Emulator functions are shared with PGEC2/PGED2) #pragma config LPCFG = ON // Low power regulator control (Low voltage regulator controlled in sw by RETEN bit) #pragma config GWRP = OFF // General Segment Write Protect (Disabled) #pragma config GCP = OFF // General Segment Code Protect (Code protection is disabled) #pragma config JTAGEN = OFF // JTAG Port Enable (Disabled) /// オシロ用変数 // グローバル変数、定数定義 int Index,POT,SW; #define Max_Size 528 // サンプリング数(512+16) __attribute__((far)) unsigned int Buffer[Max_Size]; // Max 528 /// 関数プロトタイピング void Init(void); // ADC & DMA初期化 void Oscillo(void); void AxisDraw(void); /*********** メイン関数 **************************/ int main(void){ int i; /// クロックの設定 8MHz→96MHz÷3=32MHz CLKDIVbits.RCDIV = 0; // 1/1 8MHz CLKDIVbits.CPDIV = 0; // 32/1= 32MHz /// I/Oの初期設定 TRISB = 0xFF3F; // RB1-5(OPアンプ+AN4pin), RB12〜 RB15:DSW 4bit is Input TRISD = 0; // すべてOutput:LCD制御信号:RD7=RS, RD6=CS/, RD5=WR/, RD4=RST/, RD1=DEBUG LED TRISE = 0; // すべてOutput:LCDデータ 8bit:RE0〜 RE7 TRISF = 0x0020; // RF5 input(今回の実験では未使用だが後閑さんの設定にしておく) TRISG = 0x02C0; // RG6,7,9 Input(OPアンプpin) LATDbits.LATD1= 0; // DEBUG LED 消灯 CNPU1bits.CN2PUE = 1; // RB0 Pullup(今回の実験では未使用だが後閑さんの設定にしておく) CNPU1bits.CN12PUE = 1; // RB15=DSW_b3 Pullup CNPU3bits.CN32PUE = 1; // RB14=DSW_b2 Pullup CNPU2bits.CN31PUE = 1; // RB13=DSW_b1 Pullup CNPU2bits.CN30PUE = 1; // RB12=DSW_b0 Pullup /// アナログピン指定 ANSF = 0; // すべてデジタル ANSB = 0; // いったんデジタルにセット ANSBbits.ANSB1 = 1; // OA2NB ANSBbits.ANSB2 = 1; // OA2NC ANSBbits.ANSB3 = 1; // OA2OUT ANSBbits.ANSB4 = 1; // AN4 ADC Input ANSBbits.ANSB5 = 1; // OA1OUT ANSG = 0; // いったんデジタルにセット ANSGbits.ANSG6 = 1; // OA1PB ANSGbits.ANSG7 = 1; // OA1NE ANSGbits.ANSG9 = 1; // DAC1OUT /// タイマ2設定(A/D変換トリガ用) T2CON = 0; // Prescaler 1/1 TMR2 = 0; // カウンタクリア PR2 = 3; // 250nsec period (4MHz) // 液晶表示器の初期化 lcd_Init(); lcd_Clear(BLACK); lcd_Str(0, 0, "Start Oscillo", CYAN, BLACK); Delayms(1000); /// DMA、ADC初期設定 Init(); /// ADC Start & Ready DMA ADSTATLbits.SL0IF = 0; // ADC Flag Clear DMACH0bits.CHEN = 1; // DMA Channel Enable & Start IFS0bits.DMA0IF = 0; // DMA Interrupt Flag Reset /// 変数初期化 // Index = 0; // 初期状態にセット POT = 512; // センターレベル固定 /// メイン・ループ while(1){ T2CONbits.TON = 0; // タイマ2停止 TMR2 = 0; // タイマ2リセット /// Input Switch:サンプル周期設定 SW = (~PORTB & 0xF000) >> 12; // 10進スイッチの入力 /// スイッチの値により各処理へ分岐 switch(SW){ case 0: // 10usec/div:サンプル周期= 0.25u PR2= 3; break; case 1: // 20usec/div:サンプル周期= 0.5u PR2= 7; break; case 2: // 50usec/div:サンプル周期= 1.25u PR2= 19; break; case 3: // 100usec/div:サンプル周期= 2.5u PR2= 39; break; case 4: // 200usec/div:サンプル周期= 5u PR2= 79; break; case 5: // 500usec/div:サンプル周期= 12.5u PR2= 199; break; case 6: // 1msec/div:サンプル周期= 25u PR2= 399; break; case 7: // 2msec/div:サンプル周期= 50u PR2= 799; break; case 8: // 5msec/div:サンプル周期= 125u PR2= 1999; break; case 9: // 10msec/div:サンプル周期= 250u PR2= 3999; break; default: break; } //// Max_Size回サンプリング(DMA転送)→転送元:ADRES0(AD変換結果レジスタ)/転送先バッファ:Buffer[512+16] Index = 0; // バッファインデックス初期化 /// Max_Size回サンプリング終了待ち T2CONbits.TON = 1; // タイマ2開始、サンプリング開始 while(IFS0bits.DMA0IF == 0); // Wait Max_Size sampling /// 終了後の処理 T2CONbits.TON = 0; // Stop Timer2 & ADC IFS0bits.DMA0IF = 0; // Clear DMA Interrupt Flag /// 転送先バッファ:Buffer[512+16]には、12bitのAD変換値が格納されている。 /// 一方、QVGAのY方向のドット数は、240ドットしかないので、12bitも必要ない。 /// なので、2ビット右にシフトして、10bit精度に落とす。 for(i=0; i<528; i++){ Buffer[i]= Buffer[i] >> 2; } /// オシロ描画処理(Buffer+16の位置から描画が基本。先頭16個は捨てる。) Oscillo(); // Disp. Oscillo Delayms(1000); } } /*********************************************************************** * オシロスコープ表示、保存したデータを表 * トリガを検出してその位置から320データ表示 * トリガが一致しなければ最初から320データ表示する * * 転送元:ADRES0(AD変換結果レジスタ)/転送先バッファ:Buffer[512+16] * Buffer+16の位置から描画が基本。先頭16個は捨てる。 **************************************************************************/ void Oscillo(void){ int i,x, Point; AxisDraw(); // 座標表示 Point = -1; // 最初のデータ /// トリガチェック /// Buffer[0]〜[15]のデータは捨てる。(パイプラインが詰まるまで、最高速:4Mspsの性能が出ないため→後閑さんの説明) /// なので、チェック対象のデータは、Buffer[16]〜 190ワード分の、Buiffer[205]までとする。 for(x=16; x<206; x++){ if((Buffer[x] < POT) && (Buffer[x+5] >= POT)){ Point = x; continue; } } /// トリガ成立、その位置から波形表示 if(Point != -1){ LATDbits.LATD1 = 1; // LED ON for(i=1; i<=320; i++) { lcd_Line(i, Buffer[i+Point-1]*5/22, i, Buffer[i+Point]*5/22, MAGENTA); } } // トリガ不成立、最初から表示する else { LATDbits.LATD1 = 0; // LED OFF for(i=1; i<=320; i++){ lcd_Line(i, Buffer[i-1]*5/22, i, Buffer[i]*5/22, MAGENTA); } } } /****************************************** * Drawing Coordinate Axis *******************************************/ void AxisDraw(void){ int i; lcd_Clear(BLACK); /// X、Y座標軸,補助線表示 for(i=0; i<319; i+=40) lcd_Line(i, 0, i, 231, BROWN); // Y axis:時間軸は、1目盛 40ドットとする。(以前は50ドット) for(i=0; i<239; i+=58) lcd_Line(0, i, 319, i, BROWN); // X axis:電圧軸は、以前のまま /* Disp. Unit Time Axis (msec/div) */ switch(SW){ case 0: lcd_Str(14, 16, "10usec/div", CYAN, BLACK); break; case 1: lcd_Str(14, 16, "20usec/div", CYAN, BLACK); break; case 2: lcd_Str(14, 16, "50usec/div", CYAN, BLACK); break; case 3: lcd_Str(14, 16, "100usec/div", CYAN, BLACK); break; case 4: lcd_Str(14, 16, "200usec/div", CYAN, BLACK); break; case 5: lcd_Str(14, 16, "500usec/div", CYAN, BLACK); break; case 6: lcd_Str(14, 16, "1msec/div", CYAN, BLACK); break; case 7: lcd_Str(14, 16, "2msec/div", CYAN, BLACK); break; case 8: lcd_Str(14, 16, "5msec/div", CYAN, BLACK); break; case 9: lcd_Str(14, 16, "10msec/div", CYAN, BLACK); break; default: break; } } /************************************************** * ハードウェア初期化 *  OPAMP, DMA、ADC、DAC **************************************************/ void Init(void){ /*** OP AMP#1 Setting ****/ AMP1CONbits.AMPOE = 1; // Output Enable AMP1CONbits.NINSEL = 5; // OA1NE select(RG7) AMP1CONbits.PINSEL = 2; // OA1PB select(RG6) AMP1CONbits.SPDSEL = 1; // High Power AMP1CONbits.CMPSEL = 0; // AMP select AMP1CONbits.AMPEN = 1; // AMP Enable /*** OP AMP#2 Setting ****/ AMP2CONbits.AMPOE = 1; // Output Enable(RB3) AMP2CONbits.NINSEL = 3; // OA2NC select(RB2) AMP2CONbits.PINSEL = 2; // OA2PB select(RB1) AMP2CONbits.SPDSEL = 1; // High Power AMP2CONbits.CMPSEL = 0; // AMP select AMP2CONbits.AMPEN = 1; // AMP Enable /*** DMA CH0 Setting ****/ DMACONbits.DMAEN = 1; // DMA Enable DMACONbits.PRSSEL = 0; // Fixed Priority DMAH = 0x2000; // Upper Limit DMAL = 0x800; // Lower Limit DMACH0 = 0; // Stop Channel DMACH0bits.RELOAD = 1; // Reload DMASRC, DMADST, DMACNT DMACH0bits.TRMODE = 1; // Repeat Oneshot DMACH0bits.SAMODE = 0; // Source Addrs No Increment DMACH0bits.DAMODE = 1; // Dist Addrs Increment DMACH0bits.SIZE = 0; // Word Mode(16bit) DMASRC0 = (unsigned int)&ADRES0; // From ADC Buf0 select DMADST0 = (unsigned int)&Buffer; // To Buffer select DMACNT0 = Max_Size; // DMA Counter DMAINT0 = 0; // All Clear DMAINT0bits.CHSEL = 0x2F; // Select Pipeline ADC DMACH0bits.CHEN = 1; // Channel Enable IFS0bits.DMA0IF = 0; // Flag Reset /* BandGap BUF0 Setting */ BUFCON0 = 0; BUFCON0bits.BUFSTBY = 0; // normal mode BUFCON0bits.BUFREF = 0; // 1.2V BUFCON0bits.BUFEN = 1; // BG0 Enable /* //// 以下、DACは未使用なのでコメントアウトした。 //// DACによるバイアス電圧印加はやめ、抵抗による、AVCC/2分圧とした。 //// DAC Setting DAC1DAT = 0; DAC1CONbits.DACFM = 0; // Right Justfied DAC1CONbits.DACTRIG = 0; // Immediate Update DAC1CONbits.DACTSEL = 7; // None Trigger DAC1CONbits.DACREF = 3; // Ref = BGBUF0 1.2V×2=2.4V DAC1DAT = 0x02C0; // 出力をVDD/2=1.65Vにセット DAC1CONbits.DACEN = 1; // Enable */ /*** ADC Setting ***/ ADCON1 = 0; // All Clear ADCON2 = 0; ADCON3 = 0; ADCON1bits.FORM = 0; // unsigned Integer ADCON1bits.PWRLVL = 1; // Full Power ADCON2bits.ADPWR = 3; // Always powered ADCON2bits.PVCFG = 0; // Vref+=AVDD ADCON2bits.NVCFG = 0; // Vref-=VSS ADCON2bits.BUFORG = 1; // Use Indexed Buffer ADCON2bits.BUFINT = 0; // No buffer Interrupt ADCON3bits.ADRC = 0; // Select Fsys = 16MHz ADCON3bits.ADCS = 1; // Tad = 2Tsys = 125nsec(8MHz) /** Sample List #0 setting**/ ADL0CONH = 0; ADL0CONHbits.ASEN = 0; // disable auto-scan ADL0CONHbits.SLINT = 1; // Interrupt after every convert ADL0CONHbits.SAMC = 0; // aquisition time = 0.5Tad ADL0CONHbits.WM = 0; // all write ADL0CONL = 0; ADL0CONLbits.SLSIZE = 0; // 1 channel in the List ADL0CONLbits.SLTSRC = 5; // Timer2 Trigger ADL0CONLbits.SLEN = 1; // Enable Trigger ADL0PTR = 0; // Start from first /** Select Channel **/ ADTBL0bits.ADCH = 4; // AN4-REF- /** Execute Calibration ADC **/ ADCON1bits.ADON = 1; // ADC Enable while(ADSTATHbits.ADREADY == 0); ADCON1bits.ADCAL = 1; // Calibration Start while(ADSTATHbits.ADREADY == 0); ADL0CONLbits.SAMP = 1; // Start Sample ADL0CONLbits.SAMP = 0; // Start Conversion }