|
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
大学毕业至今,做了三年的DSP开发,将稍许经验记录下来,分享一下。
2 Z( R' `2 O7 Q' O8 t) @, M 一、弄清DSP相关资源的来源及熟读手册4 W% _0 A! {; @
一般主要来源于DSP芯片厂商的官方网站,虽然现在的DSP芯片厂商都提供了中文的官方网站浏览,但我建议还是上英文的网站,其一,有些资源在中文网站上没有(关于这点,我个人认为可能是中文这边的资源未及时上传),其二,一般资料很少有中文版,中文和英文版网站上下载的其实是同一个版本;再就是,要熟悉DSP芯片厂商的官方网站,开发时允分利用官方提供的资源及支持能大大地提高开发效率;最后要注意的是,一般DSP芯片厂商会开放一个技术交流论坛,里面的管理员一般都是DSP芯片厂商的开发工程师,可以以发贴的形式获取他们的技术支持。
0 u9 @/ G% }/ |8 R1 Y6 E9 I& | 还有一处资源的来源,就是跟DSP芯片厂商有合作的第三方公司(国内),这类公司跟DSP芯片厂商有很好的接触,一般相关的DSP芯片,他们都会先行做成教育开发板,这点当然主要用于教学,所以他们会有相关的中文资料及相应的demo程序,根据这点,可以很好的借鉴他们的经验及参考他们的资料及程序,其次,他们还会出售自制的仿真器,价格比原厂的会便宜,功能上肯定没有原厂出售的仿真器全面,但足以应对基本的项目开发。 \( I' ?1 I' a) {' J0 l# d
第三处仅供参照,占据国内市场最大的两家DSP厂商TI和ADI在中国都开设的相应级别的DSP培训课程,但费用昂贵,一般都是公司派遣前去学习。
. Z8 D1 p2 V$ |/ S1 [4 `# v5 z( J 资源主要包含:& o( I2 A1 e7 V7 p1 @
Datasheet(数据手册,主要大体介绍一下DSP芯片的功能,内部结构及外设,软件及硬件一些简单介绍,主要作用是可以很快速的了解这款DSP)6 C- i9 `; Y& k
Software Tool Manuals(这个手册主要介绍的DSP时钟、存储器、电源管理等等及所有外设的使用及注意事项,其实就是寄存器的配置,完全可以称之为DSP使用手册)
) F7 ^- x; ]9 G- e3 _ Hardware Tool Manuals(这个手册主要是官方提供的原理图PCB的绘制)、Program Manuals(这个手册主要介绍编译器及内置C库的使用,汇编指令的使用及汇编语法的介绍,官方提供的仿真软件的使用)
$ S/ h5 r6 N- `4 V; y Engineer to Engineer Note(工程师笔记,这个其实就是DSP芯片自己的工程师在开发这款DSP时所写的笔记,如果你有某个地方未明白,看相应的工程师笔记是最合适的): t' K, f5 q8 J% m
Program Examples(主要是针对DSP不同的外设,官方提供的程序例子,包含C及汇编)
) ^( Z# o! a/ w' D% y 二、官方仿真软件及仿真器的使用(如不使用,可暂时跳过,因为有些DSP可基于开源的操作系统进行开发,例如uClinux)
+ }" d- i9 C: C8 b m 使用仿真软件的方法其实很简单,一般这种软件都设计成类似VC这种,你逐个去试每个菜单下的选项,此时你如配合Examples去使用,更能加深理解,不过我建议,做DSP软件开发,先简单看一下Datasheet、Software Tool Manuals和Program Manuals这三个文档再开始熟悉仿真软件的使用,当然在你熟悉时,肯定需要去不停的再去看这些文档的。仿真器的使用并没有什么需要注意的,一般的仿真器都做了仿呆处理,所以不会插反,仿真器一般都是配合仿真软件使用。(有一点要提醒的是一般DSP开发是基于C语言,如果不会C语言,请先学习C语言)& N5 V( I! `/ w0 h! j3 E
三、DSP最小系统的配置
+ c" T. ?6 P7 s1 [7 U 这部分就正式开始使用DSP了,最小系统主要指DSP的时钟及存储器系统,这时你需要对照着Software Tool Manualsh去仔细看里面的介绍及相关寄存器的配置,结合Examples及Engineer to Engineer Note,如果程序写完后,测试时钟其实很简单,用示波器直接去测量,看测量出来的时钟是否是你配置的那个数,紧接着就是测试存储器,这个测试必须写一段简单的小程序,其实主要就是测试数据总线是否能正常工作,如果在配置最小系统时出现问题,一般问题有二,一是寄存器未正确配置,解决方法是结合Examples及Engineer to Engineer Note仔细看手册,看例程,二是可能开发板上的硬件线路出了问题,解决方法是结合原理图,看线路上是否存在短路的问题,DSP工作电压是否正常等,这步可和硬件工程师一起去查。: _ v s- `$ n% W# z
四、DSP外设的使用& B/ D z2 W$ n6 F
其实这部分和配置最小系统一样,只不过某些外设上可能连接了其它的芯片,不同的功能连接的芯片不一样,此时你需要去看这些芯片的资料,然后开始编写代码,然后再测试,测试方法根据不同的功能也会不同,不过DSP开发最常用的就是使用示波器,如有音视频方面的,可借助摄像头,显示屏等等之类的;如中间开发遇到问题,方法还是一样,结合Examples及Engineer to Engineer Note仔细看手册,看例程,有一点要注意,千万不能怀疑不能实现,要对自己有信心。! N( N( G2 P" J. P. B
五、DSP优化6 \5 h: Q) J9 N. D3 g$ \6 Y
其实到这一步,你已经完全可以使用DSP了,接下来,你需要加深熟悉DSP的整个内部结构,主要包含有几个多少位的MAC,有几个多少位的ALU,有几个多少位的数据寄存器等等,还有外部数据总线上连接了哪些外设,内部数据总线是怎么连接的,并且这些数据总线是多少位,这些在Datasheet会有一张很清楚的DSP结构图,还有DSP的整个Memory Map是怎样的,片上有多少Data Memory,有多少Program Memory等等,了解这些其实就是让你知道DSP的运算性能到底可以达到多少,哪些外设会通过外部数据总线传输数据,DSP内部的寄存器是怎么传输数据的,通过这些可以帮助你解决你在开发中遇到的问题,不过最主要的是帮助你对已经编写完成的代码进行优化,我个人认为的优化方法有以下几种:8 q1 k7 M2 ~! ?
1、一般编写代码首先是用C,基于C层面优化的方法,我如下举例说几种:$ G! ]5 F) o: c3 C" S
(1)优化循环: ^ z. D9 v( I
for(i = 0;i < max;i ++)
# ]8 b' ~1 d9 @9 k1 n; d6 @ {
6 |8 Z3 E% R4 {9 f! B for(j = 0; j < max; j ++)
5 c: |1 { a6 Z+ V {
8 ]% X3 U4 B+ a2 K6 | float sum = 0.0;, |% h/ I' e1 D: d8 j
for(k = 0; k < max; k ++)6 |# m# r( a" }8 N4 C
{
7 ?% R! @) b1 r2 S# L sum += input[i * max + k] * input[j * max + k];
9 n1 @# n( F( }1 T$ h }' G. t9 u6 r0 z2 m
cover[i * max + j] = sum / max;4 c8 h9 P0 V% {% x: U% r
}& G9 V5 l+ X3 H# u6 h
}! B" S* f8 A7 Q! V q! s/ p
实例,如input[16] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16},得出的cover如下:
. j7 ]! h& y2 ^ 7 17 27 37
7 E4 s! C+ b/ S* } 17 43 69 95
# X E# }; l1 b2 O 27 69 111 153
) G _6 i) t5 A8 C0 r 37 95 153 211
* k# ~ L7 ]$ B+ A& v8 E 图示:0 ~; _3 y0 \* a8 c" |& }5 S9 |" r1 u
0 l+ e, s2 H% @* W2 k z
原理:只需要得到左上角或右上角即可,然后半个矩阵赋值给另半个矩阵即可得到整个矩阵。
/ N6 Q# g$ A4 q; J 算法优化后:+ z/ j' T$ L- R4 u7 [
for(i = 0; i < max; i ++)
* c/ G8 K* {9 ~* _; M6 }8 P {
- r2 P _1 B1 k for(j = i; j < max; j ++) // 减少一半循环
- y+ X4 p S! N: i$ Z/ ? {/ S/ }0 f. E" V& g5 {
float sum = 0.0;4 D5 x$ t; v7 o$ O& b7 U& q3 d! _
for(k = 0; k < max; k ++): a& |2 j4 N2 K& H( @
{
' w$ O% r" s0 C sum += input[i * max + k] * input[j * max + k];( R4 D9 E0 L Z9 |, B5 a$ S. x5 @
}
" g" i. |. r+ e4 x% c1 o9 \7 j cover[i * max + j] = sum / max;
+ q- Y$ [' v4 @, a/ @1 A if(i != j) // 可加可不加,消除中线上的重复赋值3 p: M: L3 t7 P
{
" e5 X- w2 G) B' F! g" g4 l cover[j *max + i] = sum / max; // 赋值给另半个矩阵* o% P; V, b' y7 A0 A5 q' x' Y
}+ I$ T7 i6 m9 i, P v' p3 m
}
% E! Z; R1 ?: s" |. \4 o; q0 S" T }
x4 I* T3 Q# ?, Q3 g$ \/ O1 G (2)条件跳转(使用条件跳转会在流水线中浪费更多的周期)
- S- D/ r+ ?! g8 S k = k -1;
6 n$ f- b4 h! o. ~6 E0 A% \# } if(k < -1)2 ~- A3 Y# r4 ~ r9 k# i+ A3 A
{$ \1 i/ u0 x9 E5 Z9 x" U" o0 r
k = -1;# l) t) V" {" T, I
}. m( H' ]! Q! _6 w( g8 Y
原理:C语言中的max函数在编译的过程中实际上实现的是DSP中的MAX指令。
& S; a1 v/ M/ o: w) Q1 K3 N) Y, p% i 优化后:
) P* f7 \0 @( b3 V7 ~ k = max(k-1, -1);% l6 {7 h% w5 e1 M. v) x
转换成汇编后:4 u7 h( Q B6 D$ E6 x6 \: t- A# N( N& |
R0 += -1; // R0 == k;& b8 n6 n# j! w
R1 = -1;
' f" T2 l# ~! S, ]/ g% ~+ a R0 = MAX(R0, R1);
9 [0 r9 x" n% m* Z (3)for循环中的条件跳转: S: H" V' I" O, h. ^9 o
for. X* x Z/ @" | `: Y: p4 m6 {2 s, e
{4 F& ^: R1 N, ?
if{...}else{...}% U, f( [7 Y, M- ?
}
- l/ \+ ~& `/ H2 I 原理:减少频繁的条件跳转,当然并不是所有的情况都可以这样做。
/ B# |) ? U' Y( j) G/ @% T0 G 优化后:7 F+ B" i3 e) _5 S0 J
if" M; W+ z! a; V' w7 v" s2 t' g
{
5 P* ` P, O/ A0 I% j# e for{...}
2 b9 V8 M3 w9 ?# N: l) C' C l }' c `* \8 N3 Z# r
else; ^9 q" z! Q; `4 f, B# D
{
8 Q# z' I9 }: Q; _& Z for{...}. z9 s9 `. _- A
}/ s$ d0 U# Z3 H: i& s) ?2 q0 U6 l
(4)使用断言指令来避免条件跳转
5 ?$ ]/ v. \, c: x if(A)( F/ g# u6 [- _0 p$ I* a' n
{( t, }! ?( p, X
X = exp1;
. e* L9 I- V, B x9 j }& j. g' X. R, o* A! ?& e, ?/ B* i
else9 J$ E( G4 j3 R% @: `
{
- U0 I! A) [$ C" _" U7 d, l X = exp2;
" \1 A( g2 W1 O. l3 A1 r- t } + [( B. p5 E3 t6 @: b7 q9 M, G
原理:使用断言指令IF(CC) REG = REG,只会消耗一个周期。4 g ]1 j4 I4 j4 d- m2 A _
优化后:
$ @ ?( B$ _) k( }6 \0 Q6 Z: l X = exp1;9 ~& @; v( k4 X' `; v1 k! Y$ p( W* ?. z
if(!A)
6 v2 f7 I. ]8 Y2 F+ ^ {9 u# l8 g) X2 a9 c# G# B) L: A
X = exp2;- A3 b: M+ R1 C; d c
}
. B4 \; e$ Z& c9 [( E (5)除法(取模)操作' `( o0 o. k8 o$ R/ v1 l) x7 I* M
一般DSP中不支持除法,除法操作是通过仿真的方式来进行实现,有两种,分为低精度和高精度,但都需要相大多的周期。
9 Q' p4 r4 D7 g& r 除数为2的N次方时可采用右移法。
( }2 L; t$ c' A4 U/ `+ x, K, c s5 x 如为提高性能,可采取查表的方式,这样会损失精度。
$ U2 q: c& D% M, B" J) A! F 隐藏的除法:
. F4 t: I# F- {4 b$ [ for(i = start; i < finish; i += step); Y, n3 i% l. ]5 a, Z
此时编译器会looper = (finish - start) / step 得到次数。8 l E- c6 u4 ?4 y/ U
巧妙利用不等式法测:(不过可能会产生溢出,要小心使用)+ V7 D( n! ^& C6 v
if(x / y > a / b). R9 R( ~4 W$ l' C* H! G
可转换为:
( ]5 w+ u, Z/ ` if(x * b > a * y)! i9 ^" V/ w2 x$ `; n$ l6 K4 c
(6)数据类型* b/ R* O' `# M0 t9 G$ X" U1 l- Y
对于定点DSP而言,对于浮点的操作是用仿真的方式实现的,会消耗很多周期,所以在定点DSP上对于浮点数一般是做定点化的处理,常用的方法我举一个例子:2.5 * a,其实可以转换成80 * a >> 5,不过在定点化时需要注意防溢出。
/ Q$ O+ W3 x$ Q6 m! M: k+ J# {) A 对于64位数据,也是用仿真的方式实现的,会消耗很多周期。(一般最大仅支持32位数据)
2 e+ @+ V/ Y6 ]) b$ d( i5 H 做数字信号处理操作时,如FFT,16bit的操作是比较合适的。
# k& ]8 j, M5 i/ { ] 要做控制类,条件跳转时,32bit的操作是比较合适的。
1 A' Z( e7 v3 r" b. ?. a+ a 如你的DSP的MAC是16位的,做乘法时,尽量定义成16bit数据。
: [9 B* z* L, U/ j8 p8 J% c: C (7)Memory分配* G5 h; i& b8 O6 x! N
将运算比较频繁的数据和程序段放入片内Memory,开启cache。. U4 ~$ U: |- m1 F r
如DSP能对SDRAM的不同4个bank可以同时访问,此时你可以将需要同时运算的数据放入不同的bank- _% l5 n7 M6 o1 H
(8)开启仿真软件的编译优化选项% U) v# N; C: x5 p) { z; r
在菜单相应的地方勾上即可,但值得注意时,开启自动编译优化选项后,可能会使执行的结果发生变化,所以需要测试对比一下未开编译优化选项之前的执行结果,一般来说,这个很方便,比较常用。
) h# U( T% U: J' J, l 以上8种是我常用到的优化方法,当然基于C层面算法类的优化还有很多种,这个需要慢慢积累,总结一下,一般来说先对C层面进行结构上的优化(上面的1-6均属于),然后进行Memory分配,开启仿真软件的编译优化选项,将运算频繁的程序段用汇编实现,当然如果性能满足要求,就没必要利用汇编了。+ L- D2 T0 z ~9 @ u- H
六、总结
; G* v" m! l( s+ N. i 我认为学习DSP软件开发没有什么捷径,我花了大量的文字在“弄清DSP相关资源的来源及熟读手册”上,实际上是想说,懂得获取资源是很关键的,只有熟悉手册才能完全去使用你所要开发的DSP芯片,其次DSP的主要特点就是高性能,能做一些算法类的运算,所以DSP的优化是相当重要的,关于算法优化的方法有很多种,基本可分为C结构上的优化及利用DSP的特点来进行优化,优化的学习是日易积累的,所以就要多看看相关的资料了。( a' J7 J" K! w3 V; R- \; }
快速入门的步骤如下:1 ~! y+ M! ^8 n! z* j0 B5 ~' o1 f: V
准备一开发板,简单熟悉一下手册及仿真软件,对照着例程看手册,然后再改例程,看是否能按你的意愿去实现,最小系统和每个外设都熟悉一边,恭喜你,你入门了,待续。。。 |
|