嵌入式系统常需透过数位类比转换器(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-