开发板采用ICETEK-F2812-A
FFT 计算采用TI的FFT 程序,信号发生器产生正弦波信号,输入ACD0,AD采样率为3KHz,
注意:2812输入的电压:0-3V,信号发生器的正弦波信号应有一个整的offset。
2812的主程序:
实际的FFT 运算程序:
#include "DSP281x_Device.h" // DSP281x Headerfile Include File
#include "DSP281x_Examples.h" // DSP281x Examples Include File
/* for test fft */
#include "fft.h"
// Prototype statements for functions found within this file.
interrupt void adc_isr(void);
// Global variables used in this example:
Uint16 LoopCount;
Uint16 ConversionCount;
Uint16 Voltage1[1024];
Uint16 Voltage2[1024];
#define N 1024 //FFT Length
#pragma DATA_SECTION(ipcb, "FFT ipcb");
#pragma DATA_SECTION(mag,"FFT mag");
RFFT 32 fft=RFFT 32_1024P_DEFAULTS;
long ipcb[N+2]; //In place computation buffer
long mag[N/2+1]; //Magnitude buffer
//const long win[N/2]=HAMMING128; //Window coefficient array
RFFT 32_ACQ acq=FFT RACQ_DEFAULTS; //Instance the module
main()
{
int i;
InitSysCtrl();//初始化cpu
DINT;//关中断
InitPieCtrl();//初始化pie寄存器
/* Initialize acquisition module */
acq.buffptr=ipcb;
acq.tempptr=ipcb;
acq.size=N;
acq.count=N;
acq.acqflag=1;
/* Initialize FFT module */
fft.ipcbptr=ipcb;
fft.magptr=mag;
fft.init(&fft);
IER = 0x0000;//禁止所有的中断
IFR = 0x0000;
InitPieVectTable();//初始化pie中断向量表
// Interrupts that are used in this example are re-mapped to
// ISR functions found within this file.
EALLOW; // This is needed to write to EALLOW protected register
PieVectTable.ADCINT = &adc_isr;
EDIS; // This is needed to disable write to EALLOW protected registers
AdcRegs.ADCTRL1.bit.RESET = 1; // Reset the ADC module
asm(" RPT #10 || NOP"); // Must wait 12-cycles (worst-case) for ADC reset to take effect
AdcRegs.ADCTRL3.all = 0x00C8; // first power-up ref and bandgap circuits
AdcRegs.ADCTRL3.bit.ADCBGRFDN = 0x3; // Power up bandgap/reference circuitry
AdcRegs.ADCTRL3.bit.ADCPWDN = 1; // Power up rest of ADC
// Enable ADCINT in PIE
PieCtrlRegs.PIEIER1.bit.INTx6 = 1;
IER |= M_INT1; // Enable CPU Interrupt 1
EINT; // Enable Global interrupt INTM
ERTM; // Enable Global realtime interrupt DBGM
LoopCount = 0;
ConversionCount = 1;
// Configure ADC
AdcRegs.ADCMAXCONV.all = 0x0001; // Setup 2 conv's on SEQ1
AdcRegs.ADCCHSELSEQ1.bit.CONV00 = 0x0; // Setup ADCINA3 as 1st SEQ1 conv.
AdcRegs.ADCCHSELSEQ1.bit.CONV01 = 0x1; // Setup ADCINA2 as 2nd SEQ1 conv.
AdcRegs.ADCTRL2.bit.EVA_SOC_SEQ1 = 1; // Enable EVASOC to start SEQ1
AdcRegs.ADCTRL2.bit.INT_ENA_SEQ1 = 1; // Enable SEQ1 interrupt (every EOS)
// Configure EVA
// Assumes EVA Clock is already enabled in InitSysCtrl();
EvaRegs.T1CMPR = 0x0080; // Setup T1 compare value
EvaRegs.T1PR = 0x61a8; // Setup period register
EvaRegs.GPTCONA.bit.T1TOADC = 1; // Enable EVASOC in EVA
EvaRegs.T1CON.all = 0x1042; // Enable timer 1 compare (upcount mode)
// Wait for ADC interrupt
while(1)
{
//LoopCount++;
if (acq.acqflag==0) // If the samples are acquired
{
DINT;
//RFFT 32_brev(ipcb,ipcb,N);
//RFFT 32_brev(ipcb,ipcb,N); // Input samples in Real Part
fft.calc(&fft);
fft.split(&fft);
fft.mag(&fft);
for(i=0;i<N;i++)
{
mag=sqrt(mag);
}
acq.acqflag=1; // Enable the next acquisition
EINT;
}
}
}
interrupt void adc_isr(void)
{
Voltage1[ConversionCount] = AdcRegs.ADCRESULT0>>4;
acq.input=((unsigned long)Voltage1[ConversionCount])<<16;
acq.update(&acq);
// ipcb[ConversionCount]=((unsigned long)Voltage1[ConversionCount])<<16;
Voltage2[ConversionCount] = AdcRegs.ADCRESULT1 >>4;
// If 40 conversions have been logged, start over
if(ConversionCount == 1023)
{
ConversionCount = 0;
// acq.acqflag=0;
}
else ConversionCount++;
// Reinitialize for next ADC sequence
AdcRegs.ADCTRL2.bit.RST_SEQ1 = 1; // Reset SEQ1
AdcRegs.ADCST.bit.INT_SEQ1_CLR = 1; // Clear INT SEQ1 bit
PieCtrlRegs.PIEACK.all = PIEACK_GROUP1; // Acknowledge interrupt to PIE
return;
}
/*
//###########################################################################
//
// FILE: F2812_EzDSP_RAM_lnk.cmd
//
// TITLE: Linker Command File For F2812 eZdsp examples that run out of RAM
// This linker file assumes the user is booting up in Jump to H0 mode
//
//###########################################################################
//
// Ver | dd mmm yyyy | Who | Description of changes
// =====|=============|======|===============================================
// 1.00| 11 Sep 2003 | L.H. | Changes since previous version (v.58 Alpha)
// | | | Added BEGIN section to the start of H0
// | | | Removed .bss, .const and .sysmem
// | | | These are for a small memory model. All examples
// | | | use the large model.
// | | | Added .esysmem section
// | | | Changed ramfuncs section to load and run from RAM
// | | | (previously this was type DSECT)
// | | | Moved peripheral register files to DSP28_Headers_BIOS.cmd
// | | | and DSP28_Headers_nonBIOS.cmd
// | | | Added CSM_RSVD memory section in FLASHA - this region
// | | | should be programmed with all 0x0000 when using the CSM
// -----|-------------|------|-----------------------------------------------
//###########################################################################
*/
/* ======================================================
// For Code Composer Studio V2.2 and later
// ---------------------------------------
// In addition to this memory linker command file,
// add the header linker command file directly to the project.
// The header linker command file is required to link the
// peripheral structures to the proper locations within
// the memory map.
//
// The header linker files are found in <base>/DSP281x_Headers/cmd
//
// For BIOS applications add: DSP281x_Headers_nonBIOS.cmd
// For nonBIOS applications add: DSP281x_Headers_nonBIOS.cmd
========================================================= */
/* ======================================================
// For Code Composer Studio prior to V2.2
// --------------------------------------
// 1) Use one of the following -l statements to include the
// header linker command file in the project. The header linker
// file is required to link the peripheral structures to the proper
// locations within the memory map */
/* Uncomment this line to include file only for non-BIOS applications */
/* -l DSP281x_Headers_nonBIOS.cmd */
/* Uncomment this line to include file only for BIOS applications */
/* -l DSP281x_Headers_BIOS.cmd */
/* 2) In your project add the path to <base>/DSP281x_headers/cmd to the
library search path under project->build options, linker tab,
library search path (-i).
/*========================================================= */
-l rts2800.lib
-w
-stack 400h
-heap 100
MEMORY
{
PAGE 0 :
/* For this example, H0 is split between PAGE 0 and PAGE 1 */
/* BEGIN is used for the "boot to HO" bootloader mode */
/* RESET is loaded with the reset vector only if */
/* the boot is from XINTF Zone 7. Otherwise reset vector */
/* is fetched from boot ROM. See .reset section below */
//RAMM0 : origin = 0x000000, length = 0x000400
//RAMM0 : origin = 0x3f6000, length = 0x001000
BEGIN : origin = 0x3F8000, length = 0x000002
/*BEGIN : origin = 0x3F7FF6, length = 0x000002*/
PRAMH0 : origin = 0x3f8002, length = 0x000FFE
PRAMH1 : origin = 0x80000, length = 0x0FFFF /* 64K external RAM */
RESET : origin = 0x3FFFC0, length = 0x000002 /* part of boot ROM (MP/MCn=0) or XINTF zone 7 (MP/MCn=1) */
VECTORS : origin = 0x3FFFC2, length = 0x00003E /* part of boot ROM (MP/MCn=0) or XINTF zone 7 (MP/MCn=1) */
PAGE 1 :
/* For this example, H0 is split between PAGE 0 and PAGE 1 */
L0L1RAM (RW) : origin = 0x008000, length = 0x2000
RAMM1 : origin = 0x000400, length = 0x000400
DRAMH0 : origin = 0x3f9000, length = 0x001000
}
SECTIONS
{
/* Setup for "boot to H0" mode:
The codestart section (found in DSP28_CodeStartBranch.asm)
re-directs execution to the start of user code.
Place this section at the start of H0 */
codestart : > BEGIN, PAGE = 0
ramfuncs : > PRAMH0 PAGE = 0
.text : > PRAMH0, PAGE = 0
.cinit : > PRAMH0, PAGE = 0
.pinit : > PRAMH0, PAGE = 0
.switch : > PRAMH0, PAGE = 0
.reset : > RESET, PAGE = 0, TYPE = DSECT /* not used, */
FFT tf > PRAMH0, PAGE = 0
DLOG > PRAMH0, PAGE = 0
FFT ipcb ALIGN(2048) : { } > PRAMH1 PAGE 0
FFT mag > PRAMH1 PAGE 0
SINTBL : > L0L1RAM, PAGE = 1
.stack : > RAMM1, PAGE = 1
.ebss : > DRAMH0, PAGE = 1
.econst : > DRAMH0, PAGE = 1
.esysmem : > DRAMH0, PAGE = 1
.const : > DRAMH0, PAGE = 1
.sysmem : > DRAMH0, PAGE = 1
.cio : > DRAMH0, PAGE = 1
}
FFT ipcb, FFT mag 的配置必须注意。
aca.updata
可以把ipcb 输入数据与输出数据定义为同一数据,来节省内存
在开始FFT 计算时需要
DINT 屏蔽A/D采集中断,结束FFT 计算后EINT,以保证
再没有DINT A/D采集时,的截图:A/D采集不连续,
(原文件名:FFT .jpg)
引用图片
输入信号正弦Vpp 500mV,直流偏置500mV。此时输入的信号:0.5+0.5sin(2*pi*50*t)V
此时,ADC0输入的波形:2812ADC 为12位
(原文件名:FFT .jpg)
引用图片
FFT 的图形:对ADC直接FFT 变换:数据演算:
FFT 的magtude为357578 变化为电压值 357578/(n/2)/4095*3=0.5115V ,n=1024
(原文件名:FFT .jpg)
引用图片
调用2812的FFT 子程序进行变换: 数据验算 mag 格式为Q30格式,mag=sqrt(0.00726813)*3*2=0.51152V
f=17*3000/1024=49.8Hz
Ti的FFT 程序已经考虑到定点数的溢出问题,在每级的缩放系数为2,所以不用再除以N了,
(原文件名:FFT .jpg)
引用图片
最终的计算结果合实际值有一点差别。