[开发工具]

IAR编译器有问题!

[复制链接]
4973|16
手机看帖
扫描二维码
随时随地手机跟帖
janeslee|  楼主 | 2011-6-8 12:30 | 显示全部楼层 |阅读模式
虽然我一直用IAR,但近期不得不对ARM的编译能力表示怀疑,在使用CMSIS 2.0的DSP LIB中得到错误的结果,后来跟踪发现是FFT计算中的问题,举个例子:arm_radix4_butterfly_q15函数中有段C代码:
    S = pSrc[i2];         // S=0x0000D888
    in = ((int16_t) (S & 0xFFFF)) >> 2;    // in=0xFFFFF622
    S = ((S >> 2) & 0xFFFF0000) | (in & 0xFFFF);     // S=0x0000F622
    R = __QADD16(T, S);
此段程序的初衷是利用QADD16并行指令加速计算两个16位有符号数的和,高16位和低16位均需要算数右移2位。
IAR汇编代码如下:
LDR.W  R12,[R0,R6,LSL #2]   ; R12=0x0000D888
AND.W R8, R9, R12, ASR #2
UBFX    R12, R12, #2, #16
ORR.W  R8, R12, R8              ; R8=0x00003622
QADD16 R12, LR, R8

Keil汇编代码如下:
LDR      r8,[r0,r6,LSL #2]    ;r8=0x0000D888
SXTH    r9,r8
ASR      r8,r8,#2
PKHTB  r8,r8,r9,ASR #2    ;r8=0x0000F622
QADD16  r9,r10,r8

在S=0x0000D888时,经过上述处理后IAR中的S为0x00003622,Keil中的S为0x0000F622,也就是S的低16bit一个为正,一个为负,结果就差了十万八千里。
KEIL版本为4.14, IAR我尝试了6.10,6.20,均得不到正确结果,其中IAR6.20已经把CMSIS库集成,只需要勾选即可使用,但结果仍然错误。
janeslee|  楼主 | 2011-6-8 13:34 | 显示全部楼层
再加个形象说明:FFT输入序列波形:

输入序列

输入序列


IAR经FFT后输出序列波形:

IAR FFT输出序列

IAR FFT输出序列


Keil经FFT后输出序列波形:

KEIL FFT输出序列

KEIL FFT输出序列

使用特权

评论回复
janeslee|  楼主 | 2011-6-8 14:02 | 显示全部楼层
呵呵,还有老朋友在这啊, 多年没上过C51BBS了,握个手!

使用特权

评论回复
香水城| | 2011-6-8 14:14 | 显示全部楼层
试试把变量S和in都说明为int16_t的类型,然后再进行运算,否则你的第3行语句是32位的运算而不是16位运算,这应该不是编译器的问题!

使用特权

评论回复
yybj| | 2011-6-8 15:55 | 显示全部楼层
应该不是编译器的问题

使用特权

评论回复
CC2530| | 2011-6-8 16:07 | 显示全部楼层
各个变量是什么类型?

使用特权

评论回复
janeslee|  楼主 | 2011-6-8 18:07 | 显示全部楼层
源代码是完全一样的,而且不是我写的代码,是CMSIS的DSP库,可以搜索CMSIS V2.0,查看里面的arm_cfft_radix4_q15.c文件,而且IAR 6.20本身就包含这个DSPLib的库文件,不需要源代码。

S是q31_t(int32_t),in是q15_t(int16_t),这样的定义是完全正确的,其功能就是利用QADD16加速运算:
S = pSrc[i2];  //将16bit的虚部和实部合成一个32bit字
in = ((int16_t) (S & 0xFFFF)) >> 2;    // 实部/4,此处S的低16bit应该为有符号扩展成32bit并右移
S = ((S >> 2) & 0xFFFF0000) | (in & 0xFFFF);     // 虚部也/4并与实部合并
R = __QADD16(T, S);   // R = packed((ya + yc),(xa + xc))

使用特权

评论回复
mxh0506| | 2011-6-8 21:26 | 显示全部楼层
janeslee, 请问你是在用CM3做FFT吗? 我最近也在搞类似的计算, 希望不要出问题.

使用特权

评论回复
janeslee|  楼主 | 2011-6-8 21:35 | 显示全部楼层
我是用的CM4,CM3没有QADD16之类并行加速指令,应该不会有这样的问题,以前用STM32的汇编FFT库也测试正常。

使用特权

评论回复
jack_shine| | 2011-6-8 21:48 | 显示全部楼层
LZ你感到孤独吗:lol

使用特权

评论回复
janeslee|  楼主 | 2011-6-8 22:03 | 显示全部楼层
再来个测试,输入为1KHz正弦波混合白噪声,波形如下: in1KHz.jpg


Keil通过FFT并计算幅度,结果如下(横轴下方有波形是正弦内插显示所致,实际无数据点,下同):
fftmag_keil.jpg

IAR通过FFT并计算幅度,结果如下:
fftmag_iar.jpg


测试文件见附件,包含了IAR和KEIL工程,在DSP_Lib\Examples\m4_fft_test\build目录内。
CMSIS_V2.0_Test.rar (713.06 KB)

使用特权

评论回复
luckycrow| | 2011-6-9 08:10 | 显示全部楼层
是你的程序问题,要将int16_t换成无符号型的数据类型,从这点来说keil做得更加严谨。

使用特权

评论回复
CC2530| | 2011-6-9 08:33 | 显示全部楼层
貌似是IAR bug(怎么亮IAR提交呢?)

in = ((int16_t) (S & 0xFFFF)) >> 2;
程序改成:
in = ((int16_t) (S & 0xFFFF)) / 4;

使用特权

评论回复
janeslee|  楼主 | 2011-6-9 09:34 | 显示全部楼层
>>2 和/4是一样的结果,符号都有问题,而且在一样的优化级别下/4会产生多得多的代码(接近3倍)
\\    184              T = pSrc[i0];
        LDR      R4,[R6, #+0]
\\    185              in = ((int16_t) (T & 0xFFFF)) /4;
\\    186              T = ((T /4) & 0xFFFF0000) | (in & 0xFFFF);
        SXTH     R7,R4
        ASRS     R6,R4,#+1
        ADD      R4,R4,R6, LSR #+30
        AND      R4,R1,R4, ASR #+2
        ASRS     R6,R7,#+1
        ADD      R6,R7,R6, LSR #+30
        ANDS     R6,R5,R6, ASR #+2
        ORRS     R4,R6,R4


\\    184              T = pSrc[i0];
        LDR      LR,[R5, #+0]
\\    185              in = ((int16_t) (T & 0xFFFF)) >> 2;
\\    186              T = ((T >> 2) & 0xFFFF0000) | (in & 0xFFFF);
        AND      R8,R1,LR, ASR #+2
        UBFX     LR,LR,#+2,#+16
        ORR      R8,LR,R8

这个可能是IAR对表达式的理解问题,只能把这个C文件替换成汇编来解决了。

使用特权

评论回复
baidudz| | 2011-6-9 16:30 | 显示全部楼层
程序问题

使用特权

评论回复
mxh0506| | 2011-6-15 14:50 | 显示全部楼层
本帖最后由 mxh0506 于 2011-6-15 14:54 编辑

我用CM3试验计算Q15 CFFT也出了类似问题,但是同样的输入数据用Q31或F32是正常的

也许是没有完全测试的结果:
Toolchain Support
The library has been developed and tested with MDK-ARM version 4.12. The library is being tested in GCC and IAR toolchains and updates on this activity will be made available shortly.

使用特权

评论回复
lxyppc| | 2011-6-15 15:35 | 显示全部楼层
这个问题奇怪了,看样子是出在有符号16位数的右移运算上面。
楼主只有把个问题扔给IAR去解决了。
要不然就改库的写法。
in = (S & 0x8000) ?  - (int16_t)(((uint16_t) (0-S)) >> 2) : (int16_t)(((uint16_t) (S & 0xFFFF)) >> 2);

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

76

主题

160

帖子

2

粉丝