《线程》中讨论的其他部件:MSPWARE,
我在 MSP430FR5994上开发了一款使用12位 ADC 和 FFT LEA 的应用程序。 它正在进行华丽的工作。 下一步是整合 DMA 将 ADC 数据移至 RAM,这是我遇到一些困难的地方。 MSPWare 中没有任何相关的代码示例,家庭用户指南有点不透明。 在搜索论坛后,我能够将一些内容放在一起,但似乎无法正常工作。 修改后的代码将运行,但与无 DMA 应用程序相比,性能会显著下降。
ADC 在定时同时循环中以33 ks/秒的速度收集256个时间域样本。 采集后,LEA 将执行固定刻度的真实 FFT。 我想强调的是,我的问题只是如何正确实施 DMA。 CPU 中介数据传输工作正常。
正确运行的应用程序的相关部分的代码片段(省略了大量离合线)如下:
// ADC sampling using Timer_A1 sourced to SMCLK at 8 MHz
TA1CTL = TASSEL__SMCLK | MC__UP; //SMCLK, up mode
TA1CCR0 = SAMPLING_PERIOD; // PWM Period = 30 us or 33.333 kHz sampling frequency
TA1CCTL1 = OUTMOD_3; // Set/reset
TA1CCR1 = SAMPLE_TIME; // PWM Duty Cycle
ADC12CTL0 |= ADC12ON; //ADC12 on
/* ADC triggered by Timer_A1 at 33.333 kHz; ADC clock is SMCLK at 8 MHz; see 5994 data sheet
TA1.1 output selected with ADC12SHS_4; SMCLK; single-channel repeat */
ADC12CTL1 = ADC12SHS_4 | ADC12SSEL_3 | ADC12CONSEQ_2;
ADC12CTL2 = ADC12RES_2; //12-bit conversion
ADC12MCTL0 |= ADC12INCH_4; //Input on A4 (P1.4)
ADC12MCTL0 |= ADC12VRSEL_1; //ADC range between Vref and ground
ADC12IER0 |= ADC12IE0; // Enable ADC conversion-complete interrupt
while(1)
{
int16_t ADC_array[SAMPLES],*ADC;
ADC12CTL0 |= ADC12ENC;
for(k=0; k<SAMPLES; k++) //Acquire the time-sampled data
{
LPM0; //Wait for the ADC interrupt
ADC_array[k] = ADC_Output;
}
// Perform real FFT with fixed scaling on ADC data
ADC = ADC_array; //Point to first element of ADC_array
for (k=0;k<SAMPLES;k++) input[k] = *ADC++; //Copy time data to input array
status = MAP_msp_fft_fixed_q15(&fftParams, input);
msp_checkStatus(status);
for (k=0;k<SAMPLES;k++) fft_array[k] = input[k]; //Copy the complex FFT data
*** etc ***
}
#pragma vector = ADC12_B_VECTOR
__interrupt void ADC12_ISR(void)
{
switch(__even_in_range(ADC12IV, ADC12IV__ADC12RDYIFG))
{
case ADC12IV__ADC12IFG0: // Vector 12: ADC12MEM0 Interrupt
ADC_Output = ADC12MEM0;
__bic_SR_register_on_exit(LPM0_bits); // Clear CPUOFF bit from LPM0
break;
}
}
在尝试使用 DMA 时,我消除了 ADC 中断(上面的第14行)及其中断向量 ISR。 代码的新增内容:
DMACTL0 = DMA0TSEL_26; // Channel 0 trigger is ADC12 end of conversion
/* Configure Ch 0. Repeated single transfer, increment destination address,
source address unchanged, enable DMA interrupt to signal that all conversions
are complete and let DMA ISR escape from LPM0 */
DMA0CTL |= DMADT_4 + DMADSTINCR_3 + DMAIE;
DMACTL4 = DMARMWDIS; // Read-modify-write disable. Makes no difference
DMA0SZ = SAMPLES; //Allocate space for 256 ADC samples
while(1){
uint16_t ADC_array[SAMPLES],*ADC;
//Assign the DMA source and destination addresses
__data20_write_long((uintptr_t) &DMA0SA,(uintptr_t) &ADC12MEM0);
__data20_write_long((uintptr_t) &DMA0DA,(uintptr_t) &ADC_array[0]);
DMA0CTL |= DMAEN; //Enable DMA for repeated single transfers
ADC12CTL0 |= ADC12ENC; //Turn on the ADC
LPM0; //Wait for the DMA interrupt that occurs at the completion of SAMPLES number of transfers
// Perform real FFT with fixed scaling on ADC data
ADC = ADC_array; //Point to first element of ADC_array
for (k=0;k<SAMPLES;k++) input[k] = *ADC++; //Copy time data to input array
*** etc, etc ***
}
#pragma vector=DMA_VECTOR
__interrupt void DMA_ISR(void)
{
switch(__even_in_range(DMAIV,16))
{
case 0: break;
case 2: // DMA0IFG = DMA Channel 0
__bic_SR_register_on_exit(LPM0_bits);
DMA0CTL &= ~DMAIFG; //Including this line doesn't make an difference
break;
}
}
我希望有人能在拉出示波器之前发现错误。