嵌入式系統常需透過數位類比轉換器(DAC)產生類比電壓與波形。這些轉換器有時是嵌入式處理器的外部元件,有時則會整合在處理器內。無論是哪種形式,處理器都必須在適當的時間點把需要的輸出值寫入轉換器。這通常要靠計時器來中斷處理器的正常作業程序,再將所需的值寫入轉換器。如果轉換器必須產生週期波形,處理器就要從資料列表(Table)讀取下一個數值,並且遞增資料列表的指標,然後檢查資料列表的邊界以決定是否應重置該指標。
在將週期性數值寫入轉換器的過程裡,處理器必須執行許多額外的程序才能確保輸出波形符合要求。這些額外的程序所帶來的負荷須視資料表的長度、輸出波形的頻率和處理器的操作速率而定。舉例來說,若要在處理器操作頻率在1MHz的情形下,利用每個週期32筆資料點來產生1kHz的正弦波,處理器每秒就要執行3萬2000次中斷服務,這表示兩次中斷之間只有1,000,000 / 32,000 = 31.25個處理器指令週期可供使用。就算每次中斷服務只需15個時脈週期來切換環境和執行服務內容,也會佔用將近五成的處理器時間。
如果應用需要第二個類比輸出波形,處理器的負擔將變得更大,甚至無法在規定的中斷服務時間內更新兩個轉換器的資料。在這種情況下,透過特定的微控制器(如MSP430F15x/16x)便可以解決這個問題,原因在於這些元件內含2個數位類比轉換器和1個DMA控制器。DMA控制器能將資料從一個位址搬移到另一位址,完全不需處理器介入。在本文的例子裡,DMA控制器會在規定時間內將資料列表的資料移動到兩個數位類比轉換器。(圖一)就是資料移動過程的方塊圖。
此處的DMA控制器有三個獨立通道,每個通道都能設定成從任一位址移動資料到另一位址。因此,正弦波和餘弦波可使用同一份資料列表,只要讓兩個DMA通道存取列表的不同部份就能產生正弦和餘弦輸出。
另外,每個DMA通道還能獨立遞增它的來源或目標位址。在這個例子裡,每個DMA通道都設為遞增它的來源位址,目標位址則固定為各自的DAC資料暫存器。
DMA的傳輸量也能設定。只要DMA通道的資料傳輸量達到預設值,就會從原定的來源位址開始下一次傳輸。使每個DMA通道都能利用資料表形成一個環形緩衝區,並產生週期波形。
為了移動資料,每個DMA通道都需要一個觸發器(trigger)。此處是將每個轉換器的中斷旗標當成該DMA通道的觸發器。如果兩個DMA通道有可能同時觸發,就要安排其優先順序。由於這會造成某個數位類比轉換器的資料接收出現延誤,進而導致輸出訊號失真,因此轉換器的資料更新會分開處理。
這些元件所含的數位類比轉換器都能由計時器觸發,因此可將轉換器所需的下一筆資料預先載入它的資料暫存器,等到計時器觸發時再由轉換器送出新值。在這個例子裡,每個轉換器都由Timer_A1輸出訊號觸發。由於兩個轉換器使用同一個觸發訊號,它們的輸出波形會彼此同步,以維持正弦/餘弦的關係。
以下是完整的程式碼和兩個輸出波形的示波器圖形。
---------------------------------------------------------------------------------------------------------
#define FS_Val 4095
static int Sin_tab[40] = {
0.500*FS_Val,
0.598*FS_Val,
0.691*FS_Val,
0.778*FS_Val,
0.854*FS_Val,
0.916*FS_Val,
0.962*FS_Val,
0.990*FS_Val,
1.000*FS_Val,
0.990*FS_Val,
0.962*FS_Val,
0.916*FS_Val,
0.854*FS_Val,
0.778*FS_Val,
0.691*FS_Val,
0.598*FS_Val,
0.500*FS_Val,
0.402*FS_Val,
0.309*FS_Val,
0.222*FS_Val,
0.146*FS_Val,
0.084*FS_Val,
0.038*FS_Val,
0.010*FS_Val,
0.000*FS_Val,
0.010*FS_Val,
0.038*FS_Val,
0.084*FS_Val,
0.146*FS_Val,
0.222*FS_Val,
0.309*FS_Val,
0.402*FS_Val,
0.500*FS_Val,
0.598*FS_Val,
0.691*FS_Val,
0.778*FS_Val,
0.854*FS_Val,
0.916*FS_Val,
0.962*FS_Val,
0.990*FS_Val
};
void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop WDT
ADC12CTL0 = REF2_5V + REFON; // Internal 2.5V ref
//Setup DMA triggers for both DMA channels
DMACTL0 = DMA0TSEL_5 + DMA1TSEL_5; // DAC12IFG trigger
// Setup DMA0
DMA0SA = (int) Sin_tab; // Source block address
DMA0DA = DAC12_0DAT_; // Destination single address
DMA0SZ = 0x20; // Block size
DMA0CTL = DMADT_4 + DMASRCINCR_3 + DMAEN; // Rpt single ch, inc src, word-word
//Setup DAC0 Load with Timer_A, group with DAC1
DAC12_0CTL = DAC12LSEL_2 + DAC12IR + DAC12AMP_2 + DAC12IFG + DAC12ENC + DAC12GRP;
//Setup DMA1
DMA1SA = (int) Sin_tab+8; // Source block address
DMA1DA = DAC12_1DAT_; // Destination single address
DMA1SZ = 0x20; // Block size
DMA1CTL = DMADT_4 + DMASRCINCR_3 + DMAEN; // Rpt single ch, inc src, word-word
//Setup DAC1 Load with Timer_A
DAC12_1CTL = DAC12LSEL_2 + DAC12IR + DAC12AMP_2 + DAC12IFG + DAC12ENC;
//Setup Timer_A
CCTL1 = OUTMOD_3; // CCR1 set/reset
CCR1 = 1; // CCR1 PWM Duty Cycle
CCR0 = 3; // Clock period of CCR0
TACTL = TASSEL_1 + MC_1; // ACLK, upmode
//Turn Off CPU forever
LPM3;
}
---------------------------------------------------------------------------------------------------------
最後,雖然DMA傳輸動作不會用到處理器,卻仍會佔用處理器2個時脈週期,這將為處理器帶來額外負擔。儘管如此,在利用32個資料點產生1kHz弦波的例子裡,2個週期僅相當於31.25個週期的6.4%,遠小於不使用DMA時大約50%的額外負擔。另外,產生兩個波形只需4個週期或7.8%的額外負擔,但若不使用DMA則不太可能產生兩個1kHz的弦波。
---作者為TI德州儀器亞洲區市場開發工程師---
1
-more-