TMS320F28377D库函数操作(CLA+FPU实现FFT)

1.背景

最近闲下来了,就把挖的坑填了吧,刚好大家也催更的厉害

2.内存申请

首先我们需要清楚芯片内部CLA可以读取的内存区域,通过查阅手册可以看到主要集中在LS RAM区域,手册上给出了5块区域即LS0~LS5

因为CLA最高1024点的FFT,所以我们需要一个2048点的内存空间,一般是实部,一半是虚部。显然如果按照手册上的划分方式我们肯定是存不下这个巨大的数组的。所以我们要对上面三个区域进行了整合和重新划分,将第二块区域放的很大,用以存放FFT的数据,

在程序上我们在申请时要注意想指定区域去申请,特别注意数组名称要用IOBuffer这个名称,这是官方例程里的名称,我试过改其他名字,但是没有用,最后只能用这个了。我估计是和内存分配有关系,但我没有找到是什么原因,大家如果知道也可以在评论区告诉我。

这里我申请了2049个float,因为用的是1024点的FFT,大家如果用其他点数的FFT记得要以点数的两倍来申请,因为FFT一半是虚部,一半是实部,交叉用,所以是两倍,我们平常用实部即可。

3.生成信号序列

在申请完内存后我们要向其中写入信号序列

ef36271e827940bfa55449dae73a634a.png

这里用的是c语言自带的math库里的函数,生成速度有点慢,不过不重要,因为在实际中这个数据是由ADC读取来的,这里就不用其他硬件来加速了,大家记得把math.h给包含进来就行。这里注意一下,我们初始序列也是存放在刚刚申请的CLA区域内,在使用完成后这个数据便会被覆盖掉,新的数据就是FFT的结果。

4.启动CLA

在完成上述内容后我们就可以启动CLA了。这里我用的是task1来跑了,第一句话是CLA的断定语句,因为CLA里面没法加断点因此通过这个方式来加断点,如果第一次使用CLA可以忽略。后面是就是FFT了,1024,512,256都有,大家可以自己选着跑。

因为CLA是协处理器,所以在CLA跑的时候CPU是空闲下来的。原本这是件好事,不过,因为我们是专门跑FFT的,所以还要等CLA跑完才能进行下一步。这里有两种办法,一个是通过中断来等,FFT运行结束后会触发对应的中断,不过我还是嫌麻烦,就直接延时了。

5.求相位角

在完成FFT后先不要取模,这时的FFT是包含相位信息的,我们要先提前出相位角,就是对求出的FFT结果的实部与虚部进行反正切即可,程序如下

6.通过FPU取模

之后就是通过FPU来取模了,这里也比较讲究。

首先是类型的问题,我们要使用complex_float这个TI定义的类型,这是一个结构体类型,我们在申请时是一次申请几个结构体,单个结构体是包含两个float类型的,等于说是对两个float进行一次打包,如果你看FPU例程,里面比较奢华直接申请200多个结构体,一次性计算。我在使用时就只能用for循环来搞了,算一个赋值一个了。

FPU计算核心在于下面这个函数——abs_SP_CV_TMU0()

这个函数的第一项是一个地址,这个地址就是存放运算后结果的地址,float类型,第二个参数是我们申请的结构体地址,第三个是要计算的长度。在实际运算时,CPU以一个结构体为单位,单次运算一个结构体,比如这里我们是申请了一个结构体,所以CPU也就会运算第一个结构体里的两个float。

7.求幅值

幅值是最简单的了,就是基本的数学运算,函数如下

8.结果

a562c23fb1ed46e0b930ffbfa66ece3f.png原始信号

0b8f1c60be234874a3ba292eedd2f50c.png

幅值

c267507acec3476c96e2252e843156b0.png

 相角

3adef380e3a144a1848ab967a1c3db1a.png

 频率

9.程序

MyFFT.h

/*
 * MyFFT.h
 *
 *  Created on: 2023年8月10日
 *      Author: 18752
 */

#ifndef EQUIP_MYFFT_H_
#define EQUIP_MYFFT_H_

#include "MyKey.h"


#define FFTPOINT (1<<STAGE)

void FFTAngle(float *FFTAnIn,float *FFTAnOut);

void FFTAbs(float *FFTAbsIn,float *FFTAbsOut);

void FFTAmplitude(float *FFTAmIn,float *FFTAmOut);

void init_FFT_FPU(float *FFTFFIn,float *FFTFBuffer);

void RunFPUFFT(void);

void FFTTest(float *FFTTIn);

void FFT_CLA(void);

void FFT_FPU(void);

#endif /* EQUIP_MYFFT_H_ */

MyFFT.c

/*
 * MyFFT.c
 *
 *  Created on: 2023年8月10日
 *      Author: 18752
 */

#include "MyFFT.h"

#pragma DATA_SECTION(IOBuffer,"CLAData");
float IOBuffer[FFTPOINT*2+1];

#pragma DATA_SECTION(Xiang,"ramgs1");
float Xiang[FFTPOINT];

#pragma DATA_SECTION(x,"ramgs3");
complex_float x[1];

#pragma DATA_SECTION(fftout,"ramgs2");
float fftout[FFTPOINT];

#pragma DATA_SECTION(vol,"ramgs2");
float vol[FFTPOINT];

#pragma DATA_SECTION(Twiddle,"ramgs0");
float Twiddle[FFTPOINT];

#pragma DATA_SECTION(FFTBuffer,"ramgs0");
float FFTBuffer[FFTPOINT*2];


CFFT_F32_STRUCT cfft;
CFFT_F32_STRUCT_Handle hnd_cfft = &cfft;

void FFTAngle(float *FFTAnIn,float *FFTAnOut)
{
    int FFTi;
    for(FFTi=0;FFTi<FFTPOINT;FFTi++)
    {
        if(FFTAnIn[2*FFTi]>1)
        {
            FFTAnOut[FFTi]=
                    (atan2f(FFTAnIn[2*FFTi+1],FFTAnIn[2*FFTi]))*180/PI;
        }
    }
}

void FFTAbs(float *FFTAbsIn,float *FFTAbsOut)
{
    int FFTi;
//    以下为调用FPU实现取模计算
    for(FFTi=0;FFTi<FFTPOINT;FFTi++)
    {
        x[0].dat[0]=FFTAbsIn[FFTi*2];
        x[0].dat[1]=FFTAbsIn[FFTi*2+1];
        abs_SP_CV_TMU0(&(FFTAbsOut[FFTi]), x, 1);
    }
}

void FFTAmplitude(float *FFTAmIn,float *FFTAmOut)
{
    unsigned int FFTi;
    for(FFTi=0;FFTi<FFTPOINT;FFTi++)
    {
        FFTAmOut[FFTi]=FFTAmIn[FFTi]*2/FFTPOINT;
    }
    FFTAmOut[0]=(FFTAmOut[0]/2);
}

//void init_FFT_FPU(float *FFTFFIn,float *FFTFBuffer)
//{
//    hnd_cfft->InPtr   = FFTFFIn;
//    hnd_cfft->OutPtr  = FFTFBuffer;
//    hnd_cfft->Stages  = STAGE;  // FFT stages
//    hnd_cfft->FFTSize = FFTPOINT;    // FFT size
//    hnd_cfft->CoefPtr = Twiddle;  //Twiddle factor table
//    CFFT_f32_sincostable(hnd_cfft);   // Calculate twiddle factor
//    //hnd_cfft->CurrentInPtr[i]
//}
//
//void RunFPUFFT(void)
//{
//    CFFT_f32(hnd_cfft);                    // Calculate FFT
//    ESTOP0;                             //软件断点
//}

void FFTTest(float *FFTTIn)
{
    int FFTi;
    for(FFTi=0;FFTi<FFTPOINT;FFTi++)//生成信号序列
    {
        FFTTIn[2*FFTi]=220*sinf(50*2*PI*FFTi/FFTPOINT)+220/3*sinf(150*2*PI*FFTi/FFTPOINT)+220/5*sinf(250*2*PI*FFTi/FFTPOINT);
        FFTTIn[2*FFTi+1]=0;//虚部全为0
    }
}

extern unsigned char CLATest1;

void FFT_CLA(void)
{
    CLA_runTest(1);                     //启动CLA任务1
    DEVICE_DELAY_US(1000);              //等待CLA任务结束
    FFTAngle(IOBuffer,Xiang);           //求相位角
    FFTAbs(IOBuffer,fftout);            //取模
    FFTAmplitude(fftout,vol);           //求幅值
}


MyCLA.cla 

//
// Included Files
//
#include "CLA_share.h"
#include "cla_cfft.h"
#include "CLAmath.h"

extern float fVal;           //Holds the input argument to the task
extern float fResult;        //The arsine of the input argument

__interrupt void Cla1Task1 ( void )
{
    __mdebugstop();
    switch(STAGE)
    {
    case 10:
        CLA_CFFT_run1024Pt();
        break;
    case 9:
        CLA_CFFT_run512Pt();
        break;
    case 8:
        CLA_CFFT_run256Pt();
        break;
    }

//    fResult=
//                CLAsin(0.785);
}

interrupt void Cla1Task2 ( void )
{
    ;
}

interrupt void Cla1Task3 ( void )
{

}

interrupt void Cla1Task4 ( void )
{

}

interrupt void Cla1Task5 ( void )
{

}

interrupt void Cla1Task6 ( void )
{

}

interrupt void Cla1Task7 ( void )
{

}

interrupt void Cla1Task8 ( void )
{

}


main.c

#include "MyKey.h"

extern float IOBuffer[FFTPOINT*2+1];

void main(void)
{
    Device_init();
    Interrupt_initModule();
    Interrupt_initVectorTable();
    Board_init();

    CLA_init();                         //初始化CLA1

    FFTTest(IOBuffer);
    FFT_CLA();

    EINT;
    ERTM;

    ESTOP0;

    while(1)
    {
        ;
    }
}

10.结语

在28377里除了CLA,还有FPU也有FFT库,而且功能更丰富,CFFT,IFFT,逆FFT都有,程序里大家也可以看到有写注释的地方,那就是我关于FPU的FFT探索,具体等我研究透在出教程吧。

大家如果有问题也可以在评论区里提出来,我会尽力解答的,诸君共勉。

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 13
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值