This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

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

Other Parts Discussed in Thread: TM4C123GH6PM

         各位老师们好,我用tm4c123gh6pm这款launchpad做一个控制的系统,这个系统有两个环,内环使用adc0采样一个交流通道,16次硬件平均后触发中断进行一次浮点pid运算,这样内环的运行速度是62.5k左右,然后外环使用adc1采样一个交流通道和两个直流通道,64次硬件平均后触发中断,进行次1次浮点pid,这样外环运行速率就是1Msps/64/3大约为5.2K,芯片系统时钟配置为80M。

        现在的问题是,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,所以我现在一头雾水,不知道接下来该怎么调试。

        现在我自己感觉可能是1、编译器优化选项开的过大,数据精度损失。2、或者是这两个环都是在中断里面执行的,没有处理好中断应该注意的问题(中断里面的变量我后来都加上了volatile,但是没有变化)3、FPU没有开启成功,运算速度跟不上中断速度导致数据混乱4、或者难道是TM4算不了这么快,但是我确实需要这么快的运算速度啊。

        我的表达不太好,不知道有没有描述清楚问题,希望知道的老师们指点迷津,万分感谢。下面附上关键地方的代码:


/*************************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);
}

/******************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);	//清零中断标志
}
  • FPU的开启,除了软件开启外,还需要在CCS中有个选项,开启才可以的。至于你说的编译器优化开到最大,出现错误,也是有可能的,这个需要你单步调试确定。

  •         嗯嗯,谢谢您的解答,我这两天找了很久的原因,刚刚反复检查发现是程序中的所有变量虽然都定义成了volatile float类型,但是计算公式中有些 x * 0.4这种的算式,这里直接使用的0.4在编译器中是默认为double类型的,导致很多运算不能用FPU执行,改成 0.4f 之后就正常了,内环运行时间4.2uS,最快可以跑到200多k,TM4还是很强悍的。至于编译器优化选项,默认也是可以算的很快的。现在总结在这里,后面看到的坛友们不要跟我犯同样的错误。

            再次感谢xyz549040622的热心解答!