TMS320F28027之ADC
參考文檔SPRUGE5F
TMS320F28027的ADC功能:
1.12位雙採樣保持電路。
2.同時採樣和序列採樣方式。
3.全範圍電壓輸入,0V到3.3V固定,或者VREFLO到VREFHI可調。
4.系統時鐘全頻運行,無需分頻。
5.16輸入通道。
6.16個SOC配置,設置觸發,採樣窗口,通道。
7.16個獨立保存轉換結果的結果寄存器。
8.多觸發源。
9.9個靈活的PIE中斷。
SOC操作原理:
與以往的ADC類型不同,TMS320F28027的ADC爲3型,它是基於SOC的而不是基於序列的。SOC可以配置定義一個單獨通道的獨立轉換。包括三種配置:開始轉換的觸發源,轉換的通道,採樣窗口的大小。每個SOC是獨立配置的,可以有很多種觸發源,通道,採樣窗口大小的組合。如果需要,多個SOC可以配置成一樣的觸發源,通道,採樣窗口大小。這提供了一種靈活的配置方法。可以配置轉換在不同通道用不同的觸發獨立採樣。可以用一個單獨的觸發過採樣一個相同的通道。可以創建同一個觸發不同通道的轉換序列。
SOCx的觸發源由ADCSOCxCTL寄存器中的TRIGSEL和ADCINTSOCSEL1或 ADCINTSOCSEL2 寄存器配置。軟件可以通過ADCSOCFRC1寄存器產生一個SOC事件。通道和採樣窗口大小可以通過ADCSOCxCTL寄存器的CHSEL和ACQPS配置。
採樣保持窗口:
外部驅動能力的不同影響推動模擬信號速度和有效性。有一些電路需要更長的時間,使電荷正確地轉移到ADC的採樣電容。爲了滿足需求,ADC可以在SOC中獨立地控制採樣窗口的寬度。每個ADCSOCxCTL寄存器都有6位域,ACQPS,用來決定採樣保持窗口的大小。寫到這個位域的值要比期望的採樣保持窗口的包括的週期要少1。例如:位域的值爲15,那就需要16個週期來採樣。允許最少的採樣週期是7(ACQPS=6)。完成一次轉換的時間由採樣時間加轉換時間(13個ADC時鐘)組成。
ONESHOT單次轉換支持:
該模式將允許你在循環計劃的下一個SOC觸發時,執行一次循環轉換。這種模式只適用於循環輪中的通道。那些沒有配置在循環輪中觸發的通道,將會基於ADCSOCPRIORITYCTL寄存器中的SOCPRIORITY確定優先級。
ONESHOT模式對順序和同時採樣方式作用如下:
順序模式:只有在RR模式中的下一個激活的soc才允許生成。觸發其它所有的soc均會被忽略。
同時模式:如果當前RR指針指向的SOC使能了同時採樣方式,激活的SOC會從當前的指針增加到二個,這是因爲同時採樣方式會產生SOCx和SOCx+1的結果,而且SOCx+1不會被用戶觸發。
AD轉換的優先級:
當數個SOC標誌同時被設置,兩種形式的優先級順序中的一種決定它們轉換的順序。默認的決定方式是輪轉。在這種策略中,沒有某個SOC會有比其它更高的優先級。優先級由輪轉指針決定。ADCSOCPRIORITYCTL寄存器中的RRPOINTER指向最後轉換的SOC。最高優先級SOC就是下一個比RRPOINTER值大的SOC,在SOC0到SOC15中輪迴。復位時的值是32,因爲0表示轉換已經發生。當RRPOINTER值爲32,最高優先級的是SOC0。當ADCCTL1.RESET被置位或者SOCPRICTL寄存器被寫入,RRPOINTER被設備復位。
ADCSOCPRIORITYCTL寄存器的SOCPRIORITY可用於配置所有SOC的優先級。如果一個SOC被設置成高優先級,它將會當前轉換完成之後中斷輪轉,把自己插入到下一次轉換中。當轉換完成,輪轉在被中斷處繼續。如果兩個高優先級的SOC同時被觸發,編號較低的SOC被優先考慮。
同時採樣模式:
在某些應用中,保持兩個採樣的信號之間的最小延遲是非常重要的。ADC模塊包括雙採樣保持電路,允許兩個不同的通道同時採樣。同時採樣模式是通過ADCSAMPLEMODE寄存器爲兩個soc配置的。偶數SOC與接着的奇數SOC作爲一對,使用同一個使能位。這一對的動作如下:
1. 其中一個SOCx的觸發將開始一對的轉換。
2. 一對通道的轉換包括A和B對應的CHSEL的值(0-7)。
3. 兩個通道同時採樣。
4. A通道先轉換。
5. A通道轉換結束,偶數EOCx將會產生一個脈衝。B通道轉換結束,奇數EOCx將會產生一個脈衝。
6. A通道的轉換結果將會存放在偶數ADCRESULTx寄存器中,A通道的轉換結果將會存放在偶數ADCRESULTx寄存器中。
轉換結束和中斷操作:
由於有16個獨立的SOCx配置,所以有16個EOCx標誌。在序列採樣中,EOCx是直接與SOCx相關聯的。在同時採樣模式中,如上5所述。根據ADCCTL1.INTPULSEPOS的設定,EOCx脈衝將會發生在轉換開始或者結束時。
ADC模塊包括9個能被PIE標誌或者通過PIE的中斷,每個中斷都可以配置接受EOCx信號作爲中斷源。哪個EOCx信號作爲中斷源是在INTSELxNy寄存器中配置的。另外,ADCINT1和ADCINT2信號可作爲一個SOCx的觸發。這有利於建立一個連續的轉換。
上電序列:
ADC復位後是關閉狀態。在寫任意ADC寄存器之前必須置位PCLKCR0寄存器中的ADCENCLK位。啓動ADC的操作序列如下:
1. 如果希望使用外部參考源,在ADCCTL1寄存器的ADCREFSEL中使能這種模式。
2. 在ADCCTL1寄存器(5-7位ADCPWDN,ADCBGPWD,ADCREFPWD)中一起啓動參考源,帶隙和模擬電路。
3. 通過設置ADCCTL1寄存器的ADCENABLE使能ADC。
4. 在首次轉換之前延時1毫秒。
ADC校準:
任何轉換器都固有一個零偏移誤差和滿量程的增益誤差。該ADC出廠校時在25攝氏度校正兩者,同時允許用戶修改任何偏移量的校正應對應用程序環境的影響,如環境溫度。除非處在某些仿真環境下,或者需要修改出廠設置,用戶不需要執行任何特定的操作。ADC將會在設備引導過程中得到合適的校正。
廠家設定與校準功能:
在製造和測試過程中,德州儀器伴隨着一對內部晶振的設置,校正一些ADC設置。這些設置內嵌在保留的OTP memory中,作爲一個C語言可調用函數Device_cal(),在Boot ROM啓動引導過程中,程序調用這個函數寫出廠設置到各個有效寄存器。在這種情況發生時,ADC和內部振盪器不會保留他們的指定參數。如果引導程序在仿真過程中被跳過,用戶必須確保校準設置能被寫入各寄存器,以確保ADC和內部振盪器滿足在數據手冊中的要求。這可以手動調用Device_cal(),或者在應用程序中設定。
ADC零點偏移校準:
零點偏移誤差被定義爲,當轉換一個在VREFLO電壓時得到的結果。這個基本誤差會影響ADC的所有轉換,包括滿刻度的增益和線性度指標,決定了轉換器的直流精度。零點偏移誤差可能是正的,或者是負的,正的意味着轉換VREFLO時得到一個正的結果。負的意味着轉換一個高於VREFLO的電壓結果仍會是0。爲了更正這種錯誤,兩種誤差的補碼都會被寫入ADCOFFTRIM寄存器。這個寄存器的值在AD轉換結果保存到ADC結果寄存器之前會被用到。此操作被完全包含在ADC內核,所以結果的定時將不會受到影響,ADC能夠保持全動態範圍通過修改微調值。調用Device_cal()把廠家校正的零點偏移寫到ADCOFFTRIM寄存器,用戶能夠修改ADCOFFTRIM的值以減少環境造成偏移誤差。這個可以通過設置ADCCTRL1的VREFLOCONV位實現,不需要任何一個ADC通道。
如下步驟重新校準ADC偏移:
1. Set ADCOFFTRIM to80 (50h)
2. SetADCCTL1.VREFLOCONV to 1
3. Perform multiple conversions on B5 (i.e. sampleVREFLO) and take an average to account for board noise
4. Set ADCOFFTRIM to 80 (50h) minus the averageobtained in step 3
5. SetADCCTL1.VREFLOCONV to 0.
文件DSP2802x(3x)_Adc.c中的AdcOffsetSelfCal()函數實現了以上操作。
ADC滿量程增益校準:
增益錯誤是一個增量,隨着輸入電壓的增加。滿量程增益錯誤發生在輸入電壓最大值的時候。如同偏移誤差一樣,增益誤差可能是正的也可能是負的。一個正的滿量程增益誤差,意味着輸入未來最大值之前轉換結果就已經到達最大值。一個負的滿量程增益誤差,意味着轉換結果永遠達不到最大值。校正函數Device_cal()會寫一個廠家調整值到ADCREFTRIM寄存器以矯正ADC的滿量程增益誤差。這個寄存器在調用Device_cal()之後不應該被改動。
ADC偏移電流校正:
爲了增加ADC的精度,Device_cal()函數同樣會向ADC的一個寄存器寫入廠家調整值矯正偏移電流,這個寄存器在調用Device_cal()之後不應該被修改。
程序設計:
以CPU TIM0爲觸發,同時採樣兩路電壓。
程序:
/*********************************************
標題:ADC_test.c
軟件平臺:CCS v5.2
硬件平臺:C2000 LaunchPad
主頻:60M
描述:練習ADC,同時採樣模式,ADCINA4與ADCINB4
基於2802x C/C++ Header Files V1.26
author:小船
data:2012-10-08
As supplied, this project is configured for "boot to SARAM"
operation. The 2802x Boot Mode table is shown below.
$Boot_Table
While an emulator is connected to your device, the TRSTn pin = 1,
which sets the device into EMU_BOOT boot mode. In this mode, the
peripheral boot modes are as follows:
Boot Mode: EMU_KEY EMU_BMODE
(0xD00) (0xD01)
---------------------------------------
Wait !=0x55AA X
I/O 0x55AA 0x0000
SCI 0x55AA 0x0001
Wait 0x55AA 0x0002
Get_Mode 0x55AA 0x0003
SPI 0x55AA 0x0004
I2C 0x55AA 0x0005
OTP 0x55AA 0x0006
Wait 0x55AA 0x0007
Wait 0x55AA 0x0008
SARAM 0x55AA 0x000A <-- "Boot to SARAM"
Flash 0x55AA 0x000B
Wait 0x55AA Other
Write EMU_KEY to 0xD00 and EMU_BMODE to 0xD01 via the debugger
according to the Boot Mode Table above. Build/Load project,
Reset the device, and Run example
$End_Boot_Table
**********************************************/
#include "DSP28x_Project.h" // Device Headerfile and Examples Include File
#include "LEDs.h"
interrupt void tim0_isr(void);
interrupt void ADC_convered(void);
Uint16 ADCINA4_Voltage_sum = 0;
Uint16 ADCINB4_Voltage_sum = 0;
Uint16 ADCINA4_Voltage = 0;
Uint16 ADCINB4_Voltage = 0;
char convered_count = 0;
void main(void)
{
// Step 1. Initialize System Control:
// PLL, WatchDog, enable Peripheral Clocks
// This example function is found in the DSP2802x_SysCtrl.c file.
InitSysCtrl();
// Step 2. Initalize GPIO:
// This example function is found in the DSP2802x_Gpio.c file and
// illustrates how to set the GPIO to it's default state.
// InitGpio(); // Skipped for this example
// Step 3. Clear all interrupts and initialize PIE vector table:
// Disable CPU interrupts
DINT;
// Initialize PIE control registers to their default state.
// The default state is all PIE interrupts disabled and flags
// are cleared.
// This function is found in the DSP2802x_PieCtrl.c file.
InitPieCtrl();
// Disable CPU interrupts and clear all CPU interrupt flags:
IER = 0x0000;
IFR = 0x0000;
// Initialize the PIE vector table with pointers to the shell Interrupt
// Service Routines (ISR).
// This will populate the entire table, even if the interrupt
// is not used in this example. This is useful for debug purposes.
// The shell ISR routines are found in DSP2802x_DefaultIsr.c.
// This function is found in DSP2802x_PieVect.c.
InitPieVectTable();
// Step 4. Initialize all the Device Peripherals:
// This function is found in DSP2802x_InitPeripherals.c
// InitPeripherals(); // Not required for this example
// Step 5. User specific code:
InitAdc();
EALLOW;
AdcRegs.ADCSAMPLEMODE.bit.SIMULEN0 = 1; //同時採樣
AdcRegs.ADCSOC0CTL.bit.CHSEL = 4; //soc通道選擇
AdcRegs.ADCSOC1CTL.bit.CHSEL = 12;
AdcRegs.ADCSOC0CTL.bit.ACQPS = 6; //採樣時間
AdcRegs.ADCSOC1CTL.bit.ACQPS = 6;
AdcRegs.ADCSOC0CTL.bit.TRIGSEL = 1; //soc觸發選擇,TIM0
AdcRegs.ADCCTL1.bit.INTPULSEPOS = 1; //結果存入寄存器才產生中斷
PieVectTable.ADCINT1 = &ADC_convered;
AdcRegs.INTSEL1N2.bit.INT1SEL = 1; //中斷線1選擇soc1
AdcRegs.INTSEL1N2.bit.INT1CONT = 0;
AdcRegs.INTSEL1N2.bit.INT1E = 1; //中斷使能
PieCtrlRegs.PIEIER1.bit.INTx1 = 1; //使能int1.1
EDIS;
/****************設置定時器,用以觸發ADC*****************/
CpuTimer0Regs.TPR.bit.TDDR = 59;
CpuTimer0Regs.TPRH.bit.TDDRH = 0; //對輸入時鐘60分頻,60M/60=1M
CpuTimer0Regs.PRD.all = 500000;//定時0.5s
CpuTimer0Regs.TCR.bit.TRB = 1; //reload
CpuTimer0Regs.TCR.bit.TIE = 1; //使能中斷
CpuTimer0Regs.TCR.bit.TSS = 0; //開始計數
EALLOW;
PieVectTable.TINT0 = &tim0_isr;
PieCtrlRegs.PIECTRL.bit.ENPIE = 1; //使能PIE
PieCtrlRegs.PIEIER1.bit.INTx7 = 1; //使能int1.7
IER |= 0x0001;//使能GROUP1
EINT;
EDIS;
LEDs_init();
while(1)
{
};
}
interrupt void ADC_convered(void)
{
LED_toggle(LED2);
ADCINA4_Voltage_sum += AdcResult.ADCRESULT0;
ADCINB4_Voltage_sum += AdcResult.ADCRESULT1;
AdcRegs.ADCINTFLGCLR.bit.ADCINT1 = 1;
PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
convered_count++;
/*********轉換16次,取平均值*********/
if(convered_count > 15)
{
ADCINA4_Voltage = ADCINA4_Voltage_sum >> 4;//相當於除以16
ADCINB4_Voltage = ADCINB4_Voltage_sum >> 4;
ADCINA4_Voltage_sum = 0;
ADCINB4_Voltage_sum = 0;
convered_count = 0;
}
}
interrupt void tim0_isr(void)
{
LED_toggle(LED0);
PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
}
//===========================================================================
// No more.
//===========================================================================
程序運行結果: