|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
大学毕业至今,做了三年的DSP开发,将稍许经验记录下来,分享一下。3 z7 H: n6 T% R& _/ v
一、弄清DSP相关资源的来源及熟读手册
2 N) c5 k& V. ?' o1 q 一般主要来源于DSP芯片厂商的官方网站,虽然现在的DSP芯片厂商都提供了中文的官方网站浏览,但我建议还是上英文的网站,其一,有些资源在中文网站上没有(关于这点,我个人认为可能是中文这边的资源未及时上传),其二,一般资料很少有中文版,中文和英文版网站上下载的其实是同一个版本;再就是,要熟悉DSP芯片厂商的官方网站,开发时允分利用官方提供的资源及支持能大大地提高开发效率;最后要注意的是,一般DSP芯片厂商会开放一个技术交流论坛,里面的管理员一般都是DSP芯片厂商的开发工程师,可以以发贴的形式获取他们的技术支持。
" y- G6 R" S% Y, l2 b 还有一处资源的来源,就是跟DSP芯片厂商有合作的第三方公司(国内),这类公司跟DSP芯片厂商有很好的接触,一般相关的DSP芯片,他们都会先行做成教育开发板,这点当然主要用于教学,所以他们会有相关的中文资料及相应的demo程序,根据这点,可以很好的借鉴他们的经验及参考他们的资料及程序,其次,他们还会出售自制的仿真器,价格比原厂的会便宜,功能上肯定没有原厂出售的仿真器全面,但足以应对基本的项目开发。
3 i& l+ A+ J; z W/ g 第三处仅供参照,占据国内市场最大的两家DSP厂商TI和ADI在中国都开设的相应级别的DSP培训课程,但费用昂贵,一般都是公司派遣前去学习。+ s% k* H0 C O t* B
资源主要包含:
: d( r3 u& T1 K. R U Datasheet(数据手册,主要大体介绍一下DSP芯片的功能,内部结构及外设,软件及硬件一些简单介绍,主要作用是可以很快速的了解这款DSP)( K7 ~! q) V% X( l" ~# a( {
Software Tool Manuals(这个手册主要介绍的DSP时钟、存储器、电源管理等等及所有外设的使用及注意事项,其实就是寄存器的配置,完全可以称之为DSP使用手册)
$ e+ F: I: e& f1 a Hardware Tool Manuals(这个手册主要是官方提供的原理图PCB的绘制)、Program Manuals(这个手册主要介绍编译器及内置C库的使用,汇编指令的使用及汇编语法的介绍,官方提供的仿真软件的使用)
; M2 j, x X- {/ D v9 m7 E Engineer to Engineer Note(工程师笔记,这个其实就是DSP芯片自己的工程师在开发这款DSP时所写的笔记,如果你有某个地方未明白,看相应的工程师笔记是最合适的); [6 c9 e2 k8 N6 p% Q' h, D- S
Program Examples(主要是针对DSP不同的外设,官方提供的程序例子,包含C及汇编) W) M1 ^, c4 H
二、官方仿真软件及仿真器的使用(如不使用,可暂时跳过,因为有些DSP可基于开源的操作系统进行开发,例如uClinux)
% t. w. Q! Q3 ]' E0 o 使用仿真软件的方法其实很简单,一般这种软件都设计成类似VC这种,你逐个去试每个菜单下的选项,此时你如配合Examples去使用,更能加深理解,不过我建议,做DSP软件开发,先简单看一下Datasheet、Software Tool Manuals和Program Manuals这三个文档再开始熟悉仿真软件的使用,当然在你熟悉时,肯定需要去不停的再去看这些文档的。仿真器的使用并没有什么需要注意的,一般的仿真器都做了仿呆处理,所以不会插反,仿真器一般都是配合仿真软件使用。(有一点要提醒的是一般DSP开发是基于C语言,如果不会C语言,请先学习C语言)
5 J: ]. D. n% m5 Z% P& { 三、DSP最小系统的配置
* e$ {) M9 k" a* P3 {0 L% W3 ] 这部分就正式开始使用DSP了,最小系统主要指DSP的时钟及存储器系统,这时你需要对照着Software Tool Manualsh去仔细看里面的介绍及相关寄存器的配置,结合Examples及Engineer to Engineer Note,如果程序写完后,测试时钟其实很简单,用示波器直接去测量,看测量出来的时钟是否是你配置的那个数,紧接着就是测试存储器,这个测试必须写一段简单的小程序,其实主要就是测试数据总线是否能正常工作,如果在配置最小系统时出现问题,一般问题有二,一是寄存器未正确配置,解决方法是结合Examples及Engineer to Engineer Note仔细看手册,看例程,二是可能开发板上的硬件线路出了问题,解决方法是结合原理图,看线路上是否存在短路的问题,DSP工作电压是否正常等,这步可和硬件工程师一起去查。
+ W0 x4 s/ `/ Q& C" I3 L6 E 四、DSP外设的使用8 C1 v7 z; j- P( G9 P
其实这部分和配置最小系统一样,只不过某些外设上可能连接了其它的芯片,不同的功能连接的芯片不一样,此时你需要去看这些芯片的资料,然后开始编写代码,然后再测试,测试方法根据不同的功能也会不同,不过DSP开发最常用的就是使用示波器,如有音视频方面的,可借助摄像头,显示屏等等之类的;如中间开发遇到问题,方法还是一样,结合Examples及Engineer to Engineer Note仔细看手册,看例程,有一点要注意,千万不能怀疑不能实现,要对自己有信心。
. k2 r3 J) g3 N0 L3 D; }: K/ z M3 u 五、DSP优化5 I8 |+ Y: f9 z1 ?8 U) B
其实到这一步,你已经完全可以使用DSP了,接下来,你需要加深熟悉DSP的整个内部结构,主要包含有几个多少位的MAC,有几个多少位的ALU,有几个多少位的数据寄存器等等,还有外部数据总线上连接了哪些外设,内部数据总线是怎么连接的,并且这些数据总线是多少位,这些在Datasheet会有一张很清楚的DSP结构图,还有DSP的整个Memory Map是怎样的,片上有多少Data Memory,有多少Program Memory等等,了解这些其实就是让你知道DSP的运算性能到底可以达到多少,哪些外设会通过外部数据总线传输数据,DSP内部的寄存器是怎么传输数据的,通过这些可以帮助你解决你在开发中遇到的问题,不过最主要的是帮助你对已经编写完成的代码进行优化,我个人认为的优化方法有以下几种:) M. ` D& I7 q |- e; ~% i2 J
1、一般编写代码首先是用C,基于C层面优化的方法,我如下举例说几种:* a; o* \2 B; ?" b# ]- U+ N# a9 e
(1)优化循环' c5 Y6 K3 m2 N. k& f3 ]0 z8 p
for(i = 0;i < max;i ++)
( N8 R4 k. q' O- R* \( t& Q. r/ M! Q {8 z1 c2 @5 t8 M
for(j = 0; j < max; j ++)
9 P$ o( ~; \; M9 V4 W2 X1 O8 @ {
5 t+ z% |2 ^' k* o2 T* H float sum = 0.0;* A1 R7 Y- S' \" {3 f
for(k = 0; k < max; k ++)
1 z3 Z0 U. u7 v. O1 d# r0 U {! y4 e3 G& A4 _" i
sum += input[i * max + k] * input[j * max + k];0 R+ Z' A, F1 h
}
2 F% j$ u; _# s8 h$ i6 ~+ q cover[i * max + j] = sum / max;
' a" m- Y0 g T+ c }
" _2 c0 w. M# B0 u8 W }3 e9 X7 P3 ~* C* }
实例,如input[16] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16},得出的cover如下:
! ?( B4 {0 }4 e+ E0 j 7 17 27 37+ x) u( M. Z |
17 43 69 95
8 f. q' `& ?( d# W1 r 27 69 111 153
0 c8 S) B$ a; ~5 K. ^6 q 37 95 153 211. x5 A; w' \& F: f" a+ B
图示:
. b" w# b) {# F9 K- N9 I& C$ [7 H2 A
; K& V8 X, ]9 K I8 a) \ 原理:只需要得到左上角或右上角即可,然后半个矩阵赋值给另半个矩阵即可得到整个矩阵。 S- p( ]; n3 t, n4 k* U# `- v
算法优化后:! M2 e" Q! K7 a$ q7 }: @
for(i = 0; i < max; i ++): j' H! W9 e! i: r& v- L+ ~
{
1 \8 F! r8 A% M for(j = i; j < max; j ++) // 减少一半循环4 T; V0 {% @7 j
{
! `5 N/ f2 }; n- | float sum = 0.0;& {% } K7 K' y6 l/ P |
for(k = 0; k < max; k ++)
; {4 S6 r5 {9 f+ s: G$ Y4 t$ B {
/ q8 I5 L! ?6 f- Y5 E% Y sum += input[i * max + k] * input[j * max + k];
1 M. x4 C, V) N8 O8 i g7 a }
- B5 _) i; A5 u4 U5 ] cover[i * max + j] = sum / max;- q( P/ p0 F1 a6 n! B
if(i != j) // 可加可不加,消除中线上的重复赋值" L5 s4 G) c2 ^4 i8 w+ o
{
5 a. ~2 }8 A! T9 a6 A$ `; W! m cover[j *max + i] = sum / max; // 赋值给另半个矩阵
4 q. E5 |5 K1 R2 a; r }
. V2 v% U2 X% Q) t7 E5 W# d: D }6 B, e* }( F" K+ I' \
}
8 m5 J$ j z; S: V (2)条件跳转(使用条件跳转会在流水线中浪费更多的周期)
# D) s5 W6 ^+ @ k = k -1;* N- T/ {$ T. _. a' k+ Z4 P1 Q
if(k < -1)2 J7 M: k% n: a! a \" a
{5 p/ Z' a& {( F$ d
k = -1;
4 ^9 W" [$ |0 b7 m }' s# Q' M( h* h$ g1 `) E
原理:C语言中的max函数在编译的过程中实际上实现的是DSP中的MAX指令。
0 m" d( v& H' g' u' Q 优化后:* J; W9 l& @9 }$ c4 I0 \% Z
k = max(k-1, -1);
. W! n7 X; A8 ~, R 转换成汇编后:9 }. l5 i- }5 {; }
R0 += -1; // R0 == k;4 c: @# v8 B( p9 F+ D
R1 = -1;
' V# r- E3 P- ^7 F8 `5 s1 F R0 = MAX(R0, R1);3 O2 l1 k' J! G }
(3)for循环中的条件跳转
! A! J' c, h$ e+ l5 Q' e3 \ for
% Z; r6 a1 b2 [) F1 q5 D0 N {+ J0 D% M# E1 \
if{...}else{...}
6 q8 d, r- E: g8 y* n }( W) ^1 v% }! h+ R/ z
原理:减少频繁的条件跳转,当然并不是所有的情况都可以这样做。- _! V- }( e+ M! F" m
优化后:
! q+ J: |' d( f- H3 E if
0 [0 K9 X6 ?/ V9 N { w: ]# u9 C8 p7 c
for{...}
1 @% o9 Y4 w$ L* u6 n2 n }/ Y- P2 x( ^9 G8 Q& s" B
else
% B! q X3 n, f8 r {
# L* b# ?1 s C' H" B0 j for{...}1 x# {: w7 b# Y# s: s) M9 M
}- ~6 W) v- g9 n6 N8 Q
(4)使用断言指令来避免条件跳转
9 i0 E% ~# z1 [/ X if(A)* I0 K+ I) `2 r; ?( I
{* z* K! V" P# p. `; g
X = exp1;
% g! C1 _- h% @) g. x' h, {7 C }( h# F# ]( `% [2 W# x
else' c' Q! f8 C z6 A7 R
{( C& q* H' ^0 k/ g/ m
X = exp2;
7 f2 }( s7 r/ j }
9 t, c( m- e: k; Y q: h 原理:使用断言指令IF(CC) REG = REG,只会消耗一个周期。- f& U+ p+ [6 D4 M7 T/ J
优化后:
0 T+ c9 y' g$ T: t( g X = exp1;
; ?2 w3 D! S m4 E if(!A)1 N, U; {$ f9 V' |6 r3 ?! s" b; b2 a% \: s
{' y% F g2 Q7 i; Q
X = exp2;
& a( r2 y' X5 |0 l }
/ F. |6 I5 k" y* w% z5 h$ D (5)除法(取模)操作
9 Y, O4 Q& n3 ^6 P/ W4 I" g% T 一般DSP中不支持除法,除法操作是通过仿真的方式来进行实现,有两种,分为低精度和高精度,但都需要相大多的周期。
" @- M' p! e8 y! i 除数为2的N次方时可采用右移法。2 n6 r" A6 R5 w7 g1 o( ~0 I
如为提高性能,可采取查表的方式,这样会损失精度。3 }) G( C r/ f, f1 f6 ?
隐藏的除法:
9 d1 Z3 S% r# ?8 u0 E4 f for(i = start; i < finish; i += step)
5 Z: U, \: W0 B3 U* e: J 此时编译器会looper = (finish - start) / step 得到次数。' e" n [7 u9 Z, o7 d( H3 W
巧妙利用不等式法测:(不过可能会产生溢出,要小心使用)
; Y; B2 @- ^+ f; n5 y% x+ P if(x / y > a / b)
: O+ w7 r. ], c% \ 可转换为:
" R: w/ K- x: J7 a1 U" B/ { if(x * b > a * y)! ]% `, @& R" m0 P7 {
(6)数据类型1 a" A* n, e7 E# z6 y
对于定点DSP而言,对于浮点的操作是用仿真的方式实现的,会消耗很多周期,所以在定点DSP上对于浮点数一般是做定点化的处理,常用的方法我举一个例子:2.5 * a,其实可以转换成80 * a >> 5,不过在定点化时需要注意防溢出。9 n0 E* F3 n3 p( T: ~ P1 M
对于64位数据,也是用仿真的方式实现的,会消耗很多周期。(一般最大仅支持32位数据)
; W/ p) R! G: f+ b' v% w' e 做数字信号处理操作时,如FFT,16bit的操作是比较合适的。
6 |7 g7 ^6 L# w; \2 Q; Q 要做控制类,条件跳转时,32bit的操作是比较合适的。! ^6 S- [) j& k; j% S- }- \" t
如你的DSP的MAC是16位的,做乘法时,尽量定义成16bit数据。
$ J' ?& q/ \8 C# V7 [7 _ (7)Memory分配, F: J* ^9 m. w, b8 d$ @
将运算比较频繁的数据和程序段放入片内Memory,开启cache。5 i: V% g$ N/ p' k9 L
如DSP能对SDRAM的不同4个bank可以同时访问,此时你可以将需要同时运算的数据放入不同的bank
6 T% c' r$ w8 c) ]/ N; ] (8)开启仿真软件的编译优化选项
) E8 f4 k# }( M$ S 在菜单相应的地方勾上即可,但值得注意时,开启自动编译优化选项后,可能会使执行的结果发生变化,所以需要测试对比一下未开编译优化选项之前的执行结果,一般来说,这个很方便,比较常用。& ~. c- _7 @( G. V
以上8种是我常用到的优化方法,当然基于C层面算法类的优化还有很多种,这个需要慢慢积累,总结一下,一般来说先对C层面进行结构上的优化(上面的1-6均属于),然后进行Memory分配,开启仿真软件的编译优化选项,将运算频繁的程序段用汇编实现,当然如果性能满足要求,就没必要利用汇编了。/ x& ~/ L$ q+ C, d {
六、总结
2 }' W+ n+ ~1 `0 @ 我认为学习DSP软件开发没有什么捷径,我花了大量的文字在“弄清DSP相关资源的来源及熟读手册”上,实际上是想说,懂得获取资源是很关键的,只有熟悉手册才能完全去使用你所要开发的DSP芯片,其次DSP的主要特点就是高性能,能做一些算法类的运算,所以DSP的优化是相当重要的,关于算法优化的方法有很多种,基本可分为C结构上的优化及利用DSP的特点来进行优化,优化的学习是日易积累的,所以就要多看看相关的资料了。" g) s, i( l4 p' W/ V/ \
快速入门的步骤如下:
: C0 a% h- q3 r/ }5 g6 d 准备一开发板,简单熟悉一下手册及仿真软件,对照着例程看手册,然后再改例程,看是否能按你的意愿去实现,最小系统和每个外设都熟悉一边,恭喜你,你入门了,待续。。。 |
|