開發目標:
使用dsPIC33F 的 ADC(模數轉換),輸入的訊號源用訊號產生器產生一個 SINE 的電壓波形,在電路板上經連線輸入到 dsPIC33F chip 的ADC Pair0 (AN0, AN1) 輸入 pin 腳在 IC 的內部進行取樣,在 dsPIC 的ADC模塊裡面將原來的電壓訊號經過取樣保持和轉換後將輸入的電壓取樣成轉化 digital (數位)的值(10 bits)位元數為十,再將此數值儲存在 dsPIC33F 內部的 Register (16 bits) 中。之後便可從記憶體中取出此數值。
將 dsPIC33F ADCBUF 中的取樣值利用 SPI 傳輸協定 (SPI 為晶片上常見的通訊協定) 將資料傳送到另一個 DAC的晶片(MCP4812) ,在 DAC 的輸出端 pin 腳輸出電壓波形,此波形將還原成SINE 的電壓波形,解析度由暫存器內的數值決定。
將 dsPIC33F ADCBUF 中的取樣值利用 SPI 傳輸協定 (SPI 為晶片上常見的通訊協定) 將資料傳送到另一個 DAC的晶片(MCP4812) ,在 DAC 的輸出端 pin 腳輸出電壓波形,此波形將還原成SINE 的電壓波形,解析度由暫存器內的數值決定。
dsPIC Function Block Diagram
dsPIC 包含 MCU 大部分具備的功能,這裡用到 ADC 和 SPI 模組,ADC 搭配 Timer 做 trigger。
ADC Initialization 初始化設定
會用到的如 ADC存入的格式,FORM會有兩種:整數和分數。由於暫存器是16位元的,所以區分方式就用存在前後 10 bits 來做區分。整數就是存在後面(LSB)十個位元,分數的方式是以Q15的格式,然後存在高(MSB)十位元。
還有與 ADC 相關的時脈 (clock) 設定,選擇 converter 的時脈來源 (Clock Source) 和分頻,每次的取樣保持轉換過程,根據 datasheet 上的描述,要 14 個 ADC 的週期才會完成一次完整的取樣轉換。由此可知從時脈計算出來的轉換需要多少的時間可以完成,去調整取出 ADC 資料的頻率。
最後一項是 ADC Trigger Source 的設定,就是選擇由何種行為來觸發每次的 ADC 取樣,常用的如 PWM 波形, Timer, 除了用硬體的方式觸發也可以用軟體中斷來觸發。
void init_ADC(void){
ADCONbits.FORM = 0;//0為整數,1為分數
//選擇轉換成數字的格式
ADCONbits.EIE = 0; //Early Interrupt disabled
ADCONbits.ORDER = 0; //Convert even channel first
ADCONbits.SEQSAMP = 0; //Select simultaneous sampling
/*ADC的時脈*/
ADCONbits.ADCS = 5;
//ADC clock = FADC/6 = 120MHz / 6 = 20MHz
/* Tad = 1/ADC clock 轉換1次要 14*Tad = (ADC clock/14) */
// 控制 ADC clock 的分頻,由Tc 取得 主 clock後轉換成 ADC 的 clock 當TADC
/*使用an0取樣*/
ADPCFGbits.PCFG0 = 0; //select CH0 as analog pin
ADPCFGbits.PCFG1 = 0; //select CH1 as analog pin
/*中斷設置*/
IFS6bits.ADCP0IF = 0; //Clear ADC Pair 0 interrupt flag
IPC27bits.ADCP0IP = 5; //Set ADC Pair 0 interrupt priority
IEC6bits.ADCP0IE = 1; //Enable the ADC Pair 0 interrupt
ADSTATbits.P0RDY = 0; //Clear Pair 0 data ready bit
ADCPC0bits.IRQEN0 = 1; //Enable ADC Interrupt pair 0
/* 用Timer triggle ADC 觸發完才進行下次轉換*/
/*觸發源設置 Timer1 */
ADCPC0bits.TRGSRC0 = 12; //ADC Pair 0 triggered by Timer1
}
ADC Clock Source Select
figure 1. Auxiliary Clock GenerationFRCSEL / ENAPLL / SELACLK / APSTSCLR Control Bits
上述這些位元決定輔助時脈 (ACLK) 的來源和分頻,給出最後的時脈 (clock) 進入到 ADC模組使用後再分頻。
ACLKCONbits.FRCSEL = 1; // FRC provides input for Auxiliary PLL (x16)
ACLKCONbits.SELACLK = 1; // Auxiliary Ocillator provides clock source forADC
ACLKCONbits.APSTSCLR = 7; // Divide Auxiliary clock by 1
ACLKCONbits.ENAPLL = 1; // Enable Auxiliary PLL
Final Output ACLK to ADC:
ADC Aux Clock = 7.37*16/1 = 120 MHz
{
T1CONbits.TON=0;
T1CONbits.TSIDL=0 ;
T1CONbits.TGATE=0;
T1CONbits.TCKPS=0; //Timer1分頻選擇
T1CONbits.TCS=0; // Timer Clock Source Select bit,Internal clock (FOSC/2)
TMR1=0x00;
/*修改PR1*/
// 40M/250 = 160 kHz ; Triggle period time = 6.25us
PR1=248; //Timer interrupt=FCY/TCKPS/PRn+1
/* Timer interrupt setup */
IPC0bits.T1IP= 0x01;
IFS0bits.T1IF= 0;
IEC0bits.T1IE= 1;
}
根據下圖提供的資訊去設定系統要用的時脈來源 (Clock Source),選擇哪種振盪器 (Oscillator) 和有沒有鎖相迴路 (PLL) 倍頻,設定分頻,可以計算出最後的 Fcy 和 Fosc 。
根據上面兩張圖提供的資訊,選擇 system oscillator source ,設定 PLL的分頻的 M 和 N 值,及分頻的大小,計算出 Fcy 和 Fosc 。
_FOSCSEL(FNOSC_FRC); //Internal Fast RC (FRC) oscillator
_FOSC(FCKSM_CSECMD & OSCIOFNC_ON)
/* Clock Switching and Monitor */
//FCKSM_CSECMD : Clock switching is enabled, Fail-Safe Clock Monitor is Disabled
/* OSC2 Pin Function */
//OSCIOFNC_ON : OSC2 is general purpose digital I/O pin
PLLFBD=41; // M = PLLFBD + 2
CLKDIVbits.PLLPOST=0; // N1 = 2
CLKDIVbits.PLLPRE=0; // N2 = 2
最後 Fosc 除以2 即 Fcy 。
Final Fcy:
Fcy = (7.37*43/2/2)/2 = 40 M
TCKPS / TGATE / TCS
T1CONbits.TCKPS=0; //Timer1分頻選擇
T1CONbits.TGATE=0;
T1CONbits.TCS=0; // Timer Clock Source Select bit,Internal clock (FOSC/2)
ACLKCONbits.SELACLK = 1; // Auxiliary Ocillator provides clock source forADC
ACLKCONbits.APSTSCLR = 7; // Divide Auxiliary clock by 1
ACLKCONbits.ENAPLL = 1; // Enable Auxiliary PLL
Final Output ACLK to ADC:
ADC Aux Clock = 7.37*16/1 = 120 MHz
Timer1 Triggle setup
void init_Timer1(void){
T1CONbits.TON=0;
T1CONbits.TSIDL=0 ;
T1CONbits.TGATE=0;
T1CONbits.TCKPS=0; //Timer1分頻選擇
T1CONbits.TCS=0; // Timer Clock Source Select bit,Internal clock (FOSC/2)
TMR1=0x00;
/*修改PR1*/
// 40M/250 = 160 kHz ; Triggle period time = 6.25us
PR1=248; //Timer interrupt=FCY/TCKPS/PRn+1
/* Timer interrupt setup */
IPC0bits.T1IP= 0x01;
IFS0bits.T1IF= 0;
IEC0bits.T1IE= 1;
}
Fcy select source 系統頻率(FCY)的來源
FRC Oscillator / FRCCLK / FRCDIC / FRCDIV<2:0> / FRCDIVN
Source(Internal RC) / PLLPRE / PLLDIV / PLLPOST
根據上面兩張圖提供的資訊,選擇 system oscillator source ,設定 PLL的分頻的 M 和 N 值,及分頻的大小,計算出 Fcy 和 Fosc 。
_FOSCSEL(FNOSC_FRC); //Internal Fast RC (FRC) oscillator
_FOSC(FCKSM_CSECMD & OSCIOFNC_ON)
/* Clock Switching and Monitor */
//FCKSM_CSECMD : Clock switching is enabled, Fail-Safe Clock Monitor is Disabled
/* OSC2 Pin Function */
//OSCIOFNC_ON : OSC2 is general purpose digital I/O pin
PLLFBD=41; // M = PLLFBD + 2
CLKDIVbits.PLLPOST=0; // N1 = 2
CLKDIVbits.PLLPRE=0; // N2 = 2
最後 Fosc 除以2 即 Fcy 。
Final Fcy:
Fcy = (7.37*43/2/2)/2 = 40 M
Timer select source
新增說明文字 |
T1CONbits.TCKPS=0; //Timer1分頻選擇
T1CONbits.TGATE=0;
T1CONbits.TCS=0; // Timer Clock Source Select bit,Internal clock (FOSC/2)
ADC Calculate
取樣 / 保持過程
取樣轉換完成需要 14*Tad
/*ADC的時脈*/
ADCONbits.ADCS = 5;
//ADC clock = FADC/6 = 120MHz / 6 = 20MHz ; Tad = 0.05us
/* Tad = 1/ADC clock 轉換1次要 14*Tad = 0.7us ; 做完一次ADC的頻率 Fad = 1428 kHz */
SPI初始化
SPI 根據 Clock 的類型分成四種 Mode , 以正/負緣觸發和由高/低電位不同做區分。
設定 SPI 的 clock 由 Fcy 取得做分頻, dsPIC33F SPI 模組支援到 20 MHz。
SPI 傳輸的模式有分 8 bits 和 16 bits。
//here is the SPI setup for 20 MHz operation, Mode 0,0.
{
//PLLFBD = 41;
//CLKDIV = 0x0040; //將主clock 移到main前面作設置
SPI1CON1 = 0x013B; //0000 0001 0011 1011
/* 設置SPI的分頻 */
SPI1CON1bits.PPRE = 0b11; //Secondary Prescale bits
SPI1CON1bits.SPRE = 0b110; //Primary Prescale bits
/* Mode Select */
SPI1CON1bits.CKP = 0; //SPI1CON1<6>
SPI1CON1bits.CKE = 1; //SPI1CON1<8>
//Mode(0,0) : CKP=0; CKE=1
SPI1CON1bits.MODE16 = 0;
//Communication is word-wide 16 bits
//Communication is word-wide 16 bits
SPI1CON2 = 0x0000;
SPI1STAT = 0x8000;
}
void InitPorts(void)
{
TRISB = 0x0000; //RB全部設成輸出
/* 用 RB3 當 CS 位*/
TRISBbits.TRISB3 = 0; //RB3(11)
/* LDAC RB6 */
TRISBbits.TRISB6 = 0; //RB6(17)
/* 檢查ADC中斷用RB4腳位 */
TRISBbits.TRISB4 = 0; //RB4 as output
/* Mapping SPI output port*/
RPOR0 = 0x0700; //RP1(9):SDO1/RB1
RPOR1 = 0x0008; //RP2(10):SCK1/RB2
}
腳位初始化 SPI腳位 Mapping
void InitPorts(void){
TRISB = 0x0000; //RB全部設成輸出
/* 用 RB3 當 CS 位*/
TRISBbits.TRISB3 = 0; //RB3(11)
/* LDAC RB6 */
TRISBbits.TRISB6 = 0; //RB6(17)
/* 檢查ADC中斷用RB4腳位 */
TRISBbits.TRISB4 = 0; //RB4 as output
/* Mapping SPI output port*/
RPOR0 = 0x0700; //RP1(9):SDO1/RB1
RPOR1 = 0x0008; //RP2(10):SCK1/RB2
}
沒有留言:
張貼留言