|
EDA365欢迎您!
您需要 登录 才可以下载或查看,没有帐号?注册
x
大学毕业至今,做了三年的DSP开发,将稍许经验记录下来,分享一下。5 T4 w. X" k( c8 ^+ [( t9 |; l
一、弄清DSP相关资源的来源及熟读手册6 c+ @8 w1 ~& L/ ?6 v
一般主要来源于DSP芯片厂商的官方网站,虽然现在的DSP芯片厂商都提供了中文的官方网站浏览,但我建议还是上英文的网站,其一,有些资源在中文网站上没有(关于这点,我个人认为可能是中文这边的资源未及时上传),其二,一般资料很少有中文版,中文和英文版网站上下载的其实是同一个版本;再就是,要熟悉DSP芯片厂商的官方网站,开发时允分利用官方提供的资源及支持能大大地提高开发效率;最后要注意的是,一般DSP芯片厂商会开放一个技术交流论坛,里面的管理员一般都是DSP芯片厂商的开发工程师,可以以发贴的形式获取他们的技术支持。
7 Z# m: @% i. L J 还有一处资源的来源,就是跟DSP芯片厂商有合作的第三方公司(国内),这类公司跟DSP芯片厂商有很好的接触,一般相关的DSP芯片,他们都会先行做成教育开发板,这点当然主要用于教学,所以他们会有相关的中文资料及相应的demo程序,根据这点,可以很好的借鉴他们的经验及参考他们的资料及程序,其次,他们还会出售自制的仿真器,价格比原厂的会便宜,功能上肯定没有原厂出售的仿真器全面,但足以应对基本的项目开发。8 l% v) n; \; ]; r5 k+ G# J
第三处仅供参照,占据国内市场最大的两家DSP厂商TI和ADI在中国都开设的相应级别的DSP培训课程,但费用昂贵,一般都是公司派遣前去学习。
/ b9 {1 m. v9 F- | H 资源主要包含:( Z+ o1 U$ M; t4 }. ]8 Q
Datasheet(数据手册,主要大体介绍一下DSP芯片的功能,内部结构及外设,软件及硬件一些简单介绍,主要作用是可以很快速的了解这款DSP)9 C# x& v( L" f& C1 I
Software Tool Manuals(这个手册主要介绍的DSP时钟、存储器、电源管理等等及所有外设的使用及注意事项,其实就是寄存器的配置,完全可以称之为DSP使用手册)
9 O, h- h9 |/ U- c$ j( w" _& V' h Hardware Tool Manuals(这个手册主要是官方提供的原理图PCB的绘制)、Program Manuals(这个手册主要介绍编译器及内置C库的使用,汇编指令的使用及汇编语法的介绍,官方提供的仿真软件的使用)! @# Z& r' ^- h1 M! W/ B' T) j
Engineer to Engineer Note(工程师笔记,这个其实就是DSP芯片自己的工程师在开发这款DSP时所写的笔记,如果你有某个地方未明白,看相应的工程师笔记是最合适的): @+ {9 U5 x3 b0 u# A8 W; o
Program Examples(主要是针对DSP不同的外设,官方提供的程序例子,包含C及汇编)
7 M& F/ s+ w% Q2 `* U( I4 A9 @9 m 二、官方仿真软件及仿真器的使用(如不使用,可暂时跳过,因为有些DSP可基于开源的操作系统进行开发,例如uClinux)9 r& n& A' Z8 E' m3 T0 M5 O
使用仿真软件的方法其实很简单,一般这种软件都设计成类似VC这种,你逐个去试每个菜单下的选项,此时你如配合Examples去使用,更能加深理解,不过我建议,做DSP软件开发,先简单看一下Datasheet、Software Tool Manuals和Program Manuals这三个文档再开始熟悉仿真软件的使用,当然在你熟悉时,肯定需要去不停的再去看这些文档的。仿真器的使用并没有什么需要注意的,一般的仿真器都做了仿呆处理,所以不会插反,仿真器一般都是配合仿真软件使用。(有一点要提醒的是一般DSP开发是基于C语言,如果不会C语言,请先学习C语言)2 D) c2 v7 k% O) O4 n8 ?1 q4 F
三、DSP最小系统的配置
* Z$ s3 I- p$ J5 h9 M5 G* l6 }' _8 i 这部分就正式开始使用DSP了,最小系统主要指DSP的时钟及存储器系统,这时你需要对照着Software Tool Manualsh去仔细看里面的介绍及相关寄存器的配置,结合Examples及Engineer to Engineer Note,如果程序写完后,测试时钟其实很简单,用示波器直接去测量,看测量出来的时钟是否是你配置的那个数,紧接着就是测试存储器,这个测试必须写一段简单的小程序,其实主要就是测试数据总线是否能正常工作,如果在配置最小系统时出现问题,一般问题有二,一是寄存器未正确配置,解决方法是结合Examples及Engineer to Engineer Note仔细看手册,看例程,二是可能开发板上的硬件线路出了问题,解决方法是结合原理图,看线路上是否存在短路的问题,DSP工作电压是否正常等,这步可和硬件工程师一起去查。" C' Z( ^; D" t. e2 S
四、DSP外设的使用' L$ U, n. Q1 {/ c' t
其实这部分和配置最小系统一样,只不过某些外设上可能连接了其它的芯片,不同的功能连接的芯片不一样,此时你需要去看这些芯片的资料,然后开始编写代码,然后再测试,测试方法根据不同的功能也会不同,不过DSP开发最常用的就是使用示波器,如有音视频方面的,可借助摄像头,显示屏等等之类的;如中间开发遇到问题,方法还是一样,结合Examples及Engineer to Engineer Note仔细看手册,看例程,有一点要注意,千万不能怀疑不能实现,要对自己有信心。
3 H# a: T1 C' K* P; n 五、DSP优化
g I! @" {% T* [3 p& \ 其实到这一步,你已经完全可以使用DSP了,接下来,你需要加深熟悉DSP的整个内部结构,主要包含有几个多少位的MAC,有几个多少位的ALU,有几个多少位的数据寄存器等等,还有外部数据总线上连接了哪些外设,内部数据总线是怎么连接的,并且这些数据总线是多少位,这些在Datasheet会有一张很清楚的DSP结构图,还有DSP的整个Memory Map是怎样的,片上有多少Data Memory,有多少Program Memory等等,了解这些其实就是让你知道DSP的运算性能到底可以达到多少,哪些外设会通过外部数据总线传输数据,DSP内部的寄存器是怎么传输数据的,通过这些可以帮助你解决你在开发中遇到的问题,不过最主要的是帮助你对已经编写完成的代码进行优化,我个人认为的优化方法有以下几种:
% u) V, Z6 p0 @) h4 G, t, @* g 1、一般编写代码首先是用C,基于C层面优化的方法,我如下举例说几种:
' d0 p* q' r4 `# C (1)优化循环
: `4 w3 z+ D/ N* c M. n5 Y6 s5 a for(i = 0;i < max;i ++)* C3 w+ _9 G* o1 e5 L
{
1 v6 u& [( B! N; `% j for(j = 0; j < max; j ++)$ Z9 y1 _2 X, a4 C6 g
{
4 ?/ ^ a1 Y9 Z4 F7 u1 V |& v$ O9 m* ` float sum = 0.0;
8 }3 d4 `; c- [3 T8 Z! v' f1 p& k: w3 _ for(k = 0; k < max; k ++)
- B" m, {7 h; k _: D$ _8 ] {
- ~4 `" ~) R2 m3 \$ x sum += input[i * max + k] * input[j * max + k];
: {7 u( q2 E9 E7 f, H( q( c }
* Y& B6 x) X/ ?9 ?3 m2 n cover[i * max + j] = sum / max;
8 g& O1 w: W( [3 U/ V0 K }4 Z; [; k( |7 ~4 Z7 x7 a& d
}
+ \5 t# x* b u( |# b6 N. m 实例,如input[16] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16},得出的cover如下: o1 n0 v4 `1 \! m5 y+ [
7 17 27 37/ _) ^" C# i3 s+ X* \/ g
17 43 69 957 Y: u& l/ ~2 F5 y* w( r }
27 69 111 153) X8 C) r: o. F. ^! Z' F1 ?
37 95 153 211
) V8 L) q% A: m5 _- W( s 图示:
, v% }+ ^: ?% l
8 T2 z8 U+ @2 e7 S* X& p! t& u 原理:只需要得到左上角或右上角即可,然后半个矩阵赋值给另半个矩阵即可得到整个矩阵。2 X8 {- L3 b$ t* R# K k3 K6 y
算法优化后:
$ V" [9 d. S6 v3 }, {1 `3 X$ P; F for(i = 0; i < max; i ++)" Y; y0 Q. ~! g4 E8 ~# @4 {" l
{
: W& X5 o$ J9 M, ^ for(j = i; j < max; j ++) // 减少一半循环$ B# M0 p: }: @' ], m! d
{
& s% c: e4 C. C; s; H2 X! W float sum = 0.0;" _) R; x5 F# b- W
for(k = 0; k < max; k ++)
3 l$ a4 a" W7 o3 @/ t4 Q4 C {4 R- }2 s2 j" N( v3 l7 Z
sum += input[i * max + k] * input[j * max + k];/ H) h9 H \7 T9 i/ m6 T
}" v6 j4 A2 g5 V( k1 x) S
cover[i * max + j] = sum / max;
; x4 J3 y& O3 x if(i != j) // 可加可不加,消除中线上的重复赋值+ Z6 B" p6 S$ \
{
" M- O6 _. `9 L6 `3 M( C cover[j *max + i] = sum / max; // 赋值给另半个矩阵2 V4 \' e; x+ p' |4 C! g% m; l) N- H
}
; t: h7 }6 l! Q! T" E/ |" e }
* _5 \/ ~8 m, T8 `% s% l {0 U }% x# J L9 y1 ?
(2)条件跳转(使用条件跳转会在流水线中浪费更多的周期)5 F. B2 J! w3 s4 ^
k = k -1;
F! a3 c" o( b if(k < -1)& z3 v2 k0 _7 b! W# J% E
{+ i% P* D$ W2 r+ ~0 M& a
k = -1;
4 T3 F" w& q5 a/ r+ _8 \ }
' L' l$ l1 w, j. H 原理:C语言中的max函数在编译的过程中实际上实现的是DSP中的MAX指令。: s( z5 y6 H: I
优化后:
$ F+ Y* I* d0 T" o k = max(k-1, -1);
) E. v, i! m' x6 m9 i* P0 p& Q4 |: u 转换成汇编后:& a; D$ F5 T) _3 P; Q$ e: z
R0 += -1; // R0 == k;0 q; T4 {% _' c/ k: T% ^' h" K+ r
R1 = -1;3 C$ k6 ~/ \2 l
R0 = MAX(R0, R1);) O7 a2 o- S8 }4 F
(3)for循环中的条件跳转
8 c- Y9 p4 {! B* z) C0 I for. T& @. y9 L9 b
{
0 W. Z" w0 `# o' |* p if{...}else{...}! U. G1 T7 [( l; k. ~
}
. c7 M. z! R& @- @/ }9 [9 g 原理:减少频繁的条件跳转,当然并不是所有的情况都可以这样做。
0 w5 H2 J9 z, H% `5 d 优化后:) v* x+ t- G4 M$ ]+ f6 G; h
if
( F# `- s; B) f L( L {# J! f0 V7 i* f, x/ i4 Z$ M; w
for{...}/ i- z( G! j& I! u9 {; a8 m
}
) L3 g" S2 [8 T3 u else1 o2 C6 Y9 l y0 v0 y" D
{
; ~ A+ U0 F# o& g; P for{...}
' B! b) k9 N) U$ Q( w, @ }' Z. n" p6 G. m3 R. {3 y
(4)使用断言指令来避免条件跳转
( |: \2 m* V1 P% k: {: G h if(A)
8 _: e1 U4 L- }) D ^ {
, }* u# ]# K1 F( r9 R) n X = exp1;" k" D. a; p# D! J
}
. a! b2 Z; k1 p5 k0 |& a else
8 k% S& L$ v8 ?! q7 M/ c) b! X2 }# p {* E3 m! t) K8 R
X = exp2;
, i& E# M' [* u' z: O4 k } 3 b F% `% s" ]) W& w: N
原理:使用断言指令IF(CC) REG = REG,只会消耗一个周期。
8 ?* [ Q. _1 l1 V: N: j: b7 |; X 优化后:
5 c3 |/ \. w( x: \2 k$ F0 X X = exp1;0 I% V5 g4 j* `$ E+ b- e7 t' P
if(!A)
0 \6 _* @% `( D2 g/ Q# ^) N {
' ?6 j$ }- V- u/ Y; v X = exp2; s/ u& e, p1 H# `# W0 f4 j
}
7 U @( w! j9 T4 k" I E (5)除法(取模)操作! F9 W# A3 E* O& U5 [
一般DSP中不支持除法,除法操作是通过仿真的方式来进行实现,有两种,分为低精度和高精度,但都需要相大多的周期。; X" c5 ?3 V: E) a% P& k
除数为2的N次方时可采用右移法。5 P" ]$ L# L/ c) G E; R! S
如为提高性能,可采取查表的方式,这样会损失精度。' ]* p0 F# h0 D8 E! x
隐藏的除法:
0 \: t; X& d* i$ l0 z; E4 B for(i = start; i < finish; i += step)! E# O5 y* Q7 ?+ R* s
此时编译器会looper = (finish - start) / step 得到次数。
/ k5 {% F, d8 v0 H; E4 t9 ` 巧妙利用不等式法测:(不过可能会产生溢出,要小心使用)& I# b$ I( k% ~! H
if(x / y > a / b)
7 n/ h3 o% @1 i% w! U/ g% r. C$ ` 可转换为:3 {+ c: L8 s3 c t6 U' K% [
if(x * b > a * y)/ J6 n# |7 L+ o
(6)数据类型
: b' S. u% p k, a8 v 对于定点DSP而言,对于浮点的操作是用仿真的方式实现的,会消耗很多周期,所以在定点DSP上对于浮点数一般是做定点化的处理,常用的方法我举一个例子:2.5 * a,其实可以转换成80 * a >> 5,不过在定点化时需要注意防溢出。
: z1 P! y8 _/ } 对于64位数据,也是用仿真的方式实现的,会消耗很多周期。(一般最大仅支持32位数据)
( Q" z' b# F, p0 y 做数字信号处理操作时,如FFT,16bit的操作是比较合适的。; a5 ]/ N8 ^- o2 u1 ~2 s
要做控制类,条件跳转时,32bit的操作是比较合适的。
7 \$ V: C: G+ @; f 如你的DSP的MAC是16位的,做乘法时,尽量定义成16bit数据。
" p+ l t( i6 G- V (7)Memory分配
* V* I5 \# N8 w; z) c* V7 p% U 将运算比较频繁的数据和程序段放入片内Memory,开启cache。* z& l0 m: M" @+ C6 k @
如DSP能对SDRAM的不同4个bank可以同时访问,此时你可以将需要同时运算的数据放入不同的bank' r- I1 [, a3 |( K# m. q: R
(8)开启仿真软件的编译优化选项9 l" r/ Z6 V& l* V' Z Z3 y7 u
在菜单相应的地方勾上即可,但值得注意时,开启自动编译优化选项后,可能会使执行的结果发生变化,所以需要测试对比一下未开编译优化选项之前的执行结果,一般来说,这个很方便,比较常用。) Y7 [$ I% m% F" d! f4 n/ F
以上8种是我常用到的优化方法,当然基于C层面算法类的优化还有很多种,这个需要慢慢积累,总结一下,一般来说先对C层面进行结构上的优化(上面的1-6均属于),然后进行Memory分配,开启仿真软件的编译优化选项,将运算频繁的程序段用汇编实现,当然如果性能满足要求,就没必要利用汇编了。* a& ?/ o$ i' V' `6 ^& b
六、总结
; j1 }- L$ ?5 S- N$ h7 [$ p8 q9 | 我认为学习DSP软件开发没有什么捷径,我花了大量的文字在“弄清DSP相关资源的来源及熟读手册”上,实际上是想说,懂得获取资源是很关键的,只有熟悉手册才能完全去使用你所要开发的DSP芯片,其次DSP的主要特点就是高性能,能做一些算法类的运算,所以DSP的优化是相当重要的,关于算法优化的方法有很多种,基本可分为C结构上的优化及利用DSP的特点来进行优化,优化的学习是日易积累的,所以就要多看看相关的资料了。& i3 q' U6 j' \* C( x; h1 _
快速入门的步骤如下:
: c7 `4 d2 L1 k6 N 准备一开发板,简单熟悉一下手册及仿真软件,对照着例程看手册,然后再改例程,看是否能按你的意愿去实现,最小系统和每个外设都熟悉一边,恭喜你,你入门了,待续。。。 |
|