TIVA launchpad利用FPU进行高速双环pid运算问题

2019-03-24 10:09发布

         大家好,我用tm4c123gh6pm这款launchpad做一个控制的系统,这个系统有两个环,内环使用adc0采样一个交流通道,16次硬件平均后触发中断进行一次浮点pid运算,这样内环的运行速度是62.5k左右,然后外环使用adc1采样一个交流通道和两个直流通道,64次硬件平均后触发中断,进行次1次浮点pid,这样外环运行速率就是1Msps/64/3大约为5.2K
        现在的问题是,adc采样和外环是都没问题的,内环我通过反转IO来观察,发现根本没有60K,波形紊乱,大约只有20多k,FPU我是
#include "driverlib/fpu.h"
ROM_FPUEnable();
ROM_FPULazyStackingEnable();
这样初始化的,但是发现加不加没有明显变化,听说CCS里process options中浮点支持选项默认开启FPU我就没有深究这一点,然后我在项目属性里把编译器优化里的size-speed开到最大,没有明显变化,float-point mode选为relaxed,现在一下子速度就上去了,但是不论是速度快或慢,我总发现单步跟踪时有些语句不能到达,甚至观察有些语句比如一个0.17 * 1竟然返回了0,所以我现在一头雾水,不知道接下来该怎么调试,不知道是FPU没有开启成功造成的浮点混乱还是TM4不能运算这么快速度。
        现在我自己感觉可能是1、编译器优化选项开的过大,数据精度损失。2、或者是这两个环都是在中断里面执行的,没有处理好中断应该注意的问题(中断里面的变量我后来都加上了volatile,但是没有变化)3、FPU没有开启成功,运算速度跟不上中断速度导致数据混乱。4.不知道如果我用IQMath能不能快点,有做过的坛友们看看可不可行
        我在deyisupport上提问没有回答,来论坛找找高手们,希望大家不吝赐教,项目比较急,谢谢大家了。下面附上关键地方的代码

/******************adc初始化*********************/
void initADC(void) {
        //首先配置ADC0为电流内环高速采样中断
        ROM_ADCSequenceConfigure(ADC0_BASE, ac_cur_sequence, ADC_TRIGGER_ALWAYS, 3);//配置AD采样序列,持续触发采样,最低优先级
        ROM_ADCHardwareOversampleConfigure(ADC0_BASE,16);        //8位的硬件平均值滤波
        ROM_ADCSequenceStepConfigure(ADC0_BASE, ac_cur_sequence, 0,ADC_CTL_CH0 | ADC_CTL_IE |ADC_CTL_END);//CH0<-->PE3,差分采样CH0通道数据,步进0,采样接收产生中断信号
        ROM_ADCSequenceEnable(ADC0_BASE, ac_cur_sequence);                        //使能ADC_IN使用的采样序列
        ROM_ADCIntEnable(ADC0_BASE, ac_cur_sequence);
        ROM_IntEnable(INT_ADC0SS0);
        ROM_IntMasterEnable();                                                //使能中断
        ROM_ADCIntClear(ADC0_BASE, ac_cur_sequence);        //清零中断标志
        //然后配置ADC1为电压外环低速采样
        ROM_ADCSequenceConfigure(ADC1_BASE, other_sequence, ADC_TRIGGER_ALWAYS, 2);//配置AD采样序列,定时器触发采样,高于内环优先级
        ROM_ADCHardwareOversampleConfigure(ADC1_BASE,64);        //8位的硬件平均值滤波
        ROM_ADCSequenceStepConfigure(ADC1_BASE, other_sequence, 0,ADC_CTL_CH1);        //步骤0
        ROM_ADCSequenceStepConfigure(ADC1_BASE, other_sequence, 1,ADC_CTL_CH2);        //步骤1
        ROM_ADCSequenceStepConfigure(ADC1_BASE, other_sequence, 2,ADC_CTL_CH4 | ADC_CTL_IE |ADC_CTL_END);        //步骤2,最后产生中断
        ROM_ADCSequenceEnable(ADC1_BASE, other_sequence);                        //使能ADC_IN使用的采样序列
        ROM_ADCIntEnable(ADC1_BASE, other_sequence);
        ROM_IntEnable(INT_ADC1SS1);
        ROM_IntMasterEnable();                                                //使能中断
        ROM_ADCIntClear(ADC1_BASE, other_sequence);        //清零中断标志
}



/*************************adc0 高速电流反馈层************************/
float cur_delta;
float modle_factor_add;
uint32_t ac_cur_advalue;
void adcsq0Int() {
        ROM_GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_4, 0);
        ROM_GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_4, GPIO_PIN_4);
        ROM_ADCSequenceDataGet(ADC0_BASE, ac_cur_sequence, &ac_cur_advalue);
        ac_cur_now = ac_cur_advalue / 4095.0 * 3.3;                //当前交流电流值
        cur_delta = ac_cur_now - cur_point;                //计算当前电流与指令电流的误差
        modle_factor_add = PidDeltaCal(&pid_delta_ac, cur_delta);        //pid当前电流误差
        modle_factor = modle_factor + modle_factor_add;        //计算累加量
        modle_factor = modle_factor * 500;
        //然后调制PWM脉宽值
        if (modle_factor > 200 && modle_factor < 800)        //为了安全,限制范围在20%~80%
                adjustPWMWidth((unsigned int) (1000 - modle_factor));        //反向调制
        ROM_GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_4, 0);
        ROM_ADCIntClear(ADC0_BASE, ac_cur_sequence);
}

/*************************adc1电压外环计算*************************/
/*
* other_value[3]数组的值依次是 VAC/VDC/IDC
*/
uint32_t sin_para = 0;
float volt_delta;
float ism_factor_add;
void adcsq1Int() {
        ROM_GPIOPinWrite(GPIO_PORTA_BASE, GPIO_PIN_2, 0);
        ROM_GPIOPinWrite(GPIO_PORTA_BASE, GPIO_PIN_2, GPIO_PIN_2);
        ROM_ADCSequenceDataGet(ADC1_BASE, other_sequence, other_value);        //读取直流电压值
        dc_volt_now = other_value[1] / 4095.0 * 3.3;        //获得当前直流电压值
        dc_cur_now = other_value[2] / 4095.0 * 3.3;                //当前直流电流
        ac_volt_now = other_value[0] / 4095.0 * 3.3;        //当前交流电压
        volt_delta = dc_volt_now - volt_ref;        //计算Vdc - Vref误差值(-2048~2048)
        ism_factor_add = PidDeltaCal(&pid_delta_dc, volt_delta);//计算PID调节(输出控制在)
        ism_factor = ism_factor + ism_factor_add;                //累加增量式PID的输出结果
        //TODO 切断外环测试
        ism_factor = 1;
        sin_para++;
        ac_volt_now = 3.3 * sinf(sin_para / 104 * 2 * M_PI);
//        cur_point = ism_factor * ac_volt_now;        //计算当前电流  期望逼近量
        cur_point = ac_volt_now;        //计算当前电流期望逼近量
        if (sin_para > 104)
                sin_para = 0;
        ROM_GPIOPinWrite(GPIO_PORTA_BASE, GPIO_PIN_2, 0);
        ROM_ADCIntClear(ADC1_BASE, other_sequence);
}

此帖出自小平头技术问答
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
3条回答
tanxiaoyao
1楼-- · 2019-03-24 13:07
       原因找到了,程序中的所有变量虽然都定义成了volatile float类型,但是计算公式中有些 x * 0.4这种的算式,这里直接使用的0.4在编译器中是默认为double类型的,导致很多运算不能用FPU执行,改成 0.4f 之后就正常了,内环运行时间4.2uS,最快可以跑到200多k,TM4还是很强悍的。
      这个我也是本版的一个坛友Linchpin的笔记发现的,感谢@Linchpin的总结与分享
linda
2楼-- · 2019-03-24 15:13
< :TI_MSP430_内容页_SA7 -->
tanxiaoyao 发表于 2015-6-4 17:28
原因找到了,程序中的所有变量虽然都定义成了volatile float类型,但是计算公式中有些 x * 0.4这种的算式,这里直接使用的0.4在编译器中是默认为double类型的,导致很多运算不能用FPU执行,改成 0.4f 之后就正常了,内环运行时间4.2uS,最快可以跑到200多k,TM4还是很强悍的。
      这个我也是本版的一个坛友Linchpin的笔记发现的,感谢@Linchpin的总结与分享

解决了就好 哈哈
Linchpin
3楼-- · 2019-03-24 17:13
 精彩回答 2  元偷偷看……

一周热门 更多>

相关问题

    相关文章