EDA365电子论坛网
标题:
DSP学习经验
[打印本页]
作者:
Titianyeer
时间:
2016-5-10 17:11
标题:
DSP学习经验
大学毕业至今,做了三年的DSP开发,将稍许经验记录下来,分享一下。
0 S% E9 V- T2 m% B
一、弄清DSP相关资源的来源及熟读手册
* [4 y& o0 Q8 O9 D3 [
一般主要来源于DSP芯片厂商的官方网站,虽然现在的DSP芯片厂商都提供了中文的官方网站浏览,但我建议还是上英文的网站,其一,有些资源在中文网站上没有(关于这点,我个人认为可能是中文这边的资源未及时上传),其二,一般资料很少有中文版,中文和英文版网站上下载的其实是同一个版本;再就是,要熟悉DSP芯片厂商的官方网站,开发时允分利用官方提供的资源及支持能大大地提高开发效率;最后要注意的是,一般DSP芯片厂商会开放一个技术交流论坛,里面的管理员一般都是DSP芯片厂商的开发工程师,可以以发贴的形式获取他们的技术支持。
/ ]/ y K D8 N* d t
还有一处资源的来源,就是跟DSP芯片厂商有合作的第三方公司(国内),这类公司跟DSP芯片厂商有很好的接触,一般相关的DSP芯片,他们都会先行做成教育开发板,这点当然主要用于教学,所以他们会有相关的中文资料及相应的demo程序,根据这点,可以很好的借鉴他们的经验及参考他们的资料及程序,其次,他们还会出售自制的仿真器,价格比原厂的会便宜,功能上肯定没有原厂出售的仿真器全面,但足以应对基本的项目开发。
1 [$ }+ q0 M+ A
第三处仅供参照,占据国内市场最大的两家DSP厂商TI和ADI在中国都开设的相应级别的DSP培训课程,但费用昂贵,一般都是公司派遣前去学习。
* |: }4 b+ m) s9 l8 E: [. }/ T8 p
资源主要包含:
4 Y1 W7 `8 u& ~& O6 b+ H
Datasheet(数据手册,主要大体介绍一下DSP芯片的功能,内部结构及外设,软件及硬件一些简单介绍,主要作用是可以很快速的了解这款DSP)
3 S# C& b& s$ N
Software Tool Manuals(这个手册主要介绍的DSP时钟、存储器、电源管理等等及所有外设的使用及注意事项,其实就是寄存器的配置,完全可以称之为DSP使用手册)
4 M" Z) q( d( c' n( t
Hardware Tool Manuals(这个手册主要是官方提供的原理图PCB的绘制)、Program Manuals(这个手册主要介绍编译器及内置C库的使用,汇编指令的使用及汇编语法的介绍,官方提供的仿真软件的使用)
( s7 h' u0 a' Z( e, `; L
Engineer to Engineer Note(工程师笔记,这个其实就是DSP芯片自己的工程师在开发这款DSP时所写的笔记,如果你有某个地方未明白,看相应的工程师笔记是最合适的)
# i) H" N, r( @ |+ z1 o+ M# E
Program Examples(主要是针对DSP不同的外设,官方提供的程序例子,包含C及汇编)
) W! e3 D' u8 W
二、官方仿真软件及仿真器的使用(如不使用,可暂时跳过,因为有些DSP可基于开源的操作系统进行开发,例如uClinux)
4 }2 w J2 S3 K
使用仿真软件的方法其实很简单,一般这种软件都设计成类似VC这种,你逐个去试每个菜单下的选项,此时你如配合Examples去使用,更能加深理解,不过我建议,做DSP软件开发,先简单看一下Datasheet、Software Tool Manuals和Program Manuals这三个文档再开始熟悉仿真软件的使用,当然在你熟悉时,肯定需要去不停的再去看这些文档的。仿真器的使用并没有什么需要注意的,一般的仿真器都做了仿呆处理,所以不会插反,仿真器一般都是配合仿真软件使用。(有一点要提醒的是一般DSP开发是基于C语言,如果不会C语言,请先学习C语言)
2 F7 h( z' t6 h/ | A+ A. L
三、DSP最小系统的配置
: a D `* d9 d) U I$ g
这部分就正式开始使用DSP了,最小系统主要指DSP的时钟及存储器系统,这时你需要对照着Software Tool Manualsh去仔细看里面的介绍及相关寄存器的配置,结合Examples及Engineer to Engineer Note,如果程序写完后,测试时钟其实很简单,用示波器直接去测量,看测量出来的时钟是否是你配置的那个数,紧接着就是测试存储器,这个测试必须写一段简单的小程序,其实主要就是测试数据总线是否能正常工作,如果在配置最小系统时出现问题,一般问题有二,一是寄存器未正确配置,解决方法是结合Examples及Engineer to Engineer Note仔细看手册,看例程,二是可能开发板上的硬件线路出了问题,解决方法是结合原理图,看线路上是否存在短路的问题,DSP工作电压是否正常等,这步可和硬件工程师一起去查。
$ X) o4 c+ x0 Y) B4 L% K- \8 I
四、DSP外设的使用
/ j" K, G7 Y. X4 u
其实这部分和配置最小系统一样,只不过某些外设上可能连接了其它的芯片,不同的功能连接的芯片不一样,此时你需要去看这些芯片的资料,然后开始编写代码,然后再测试,测试方法根据不同的功能也会不同,不过DSP开发最常用的就是使用示波器,如有音视频方面的,可借助摄像头,显示屏等等之类的;如中间开发遇到问题,方法还是一样,结合Examples及Engineer to Engineer Note仔细看手册,看例程,有一点要注意,千万不能怀疑不能实现,要对自己有信心。
! v' r; j+ ^2 G; `+ C- A+ N' k
五、DSP优化
" V- z0 g% O* M" J) M6 k. H$ f
其实到这一步,你已经完全可以使用DSP了,接下来,你需要加深熟悉DSP的整个内部结构,主要包含有几个多少位的MAC,有几个多少位的ALU,有几个多少位的数据寄存器等等,还有外部数据总线上连接了哪些外设,内部数据总线是怎么连接的,并且这些数据总线是多少位,这些在Datasheet会有一张很清楚的DSP结构图,还有DSP的整个Memory Map是怎样的,片上有多少Data Memory,有多少Program Memory等等,了解这些其实就是让你知道DSP的运算性能到底可以达到多少,哪些外设会通过外部数据总线传输数据,DSP内部的寄存器是怎么传输数据的,通过这些可以帮助你解决你在开发中遇到的问题,不过最主要的是帮助你对已经编写完成的代码进行优化,我个人认为的优化方法有以下几种:
" u4 w$ J( E, \2 q: S9 ?9 c
1、一般编写代码首先是用C,基于C层面优化的方法,我如下举例说几种:
& p; E; J" Z% Z" D& V6 j6 b
(1)优化循环
* ~( G8 V# r# x9 G1 e+ P& x" m
for(i = 0;i < max;i ++)
) k, K( a) N7 x! t) V$ o T1 w; m
{
- g5 q1 m: J# Y0 `9 ?! Y
for(j = 0; j < max; j ++)
6 t( y7 L+ z3 t1 t4 F/ @$ z# b- M
{
- S- B( |, }: X" e" H) [5 H
float sum = 0.0;
3 J9 u2 J, V% ?# z( e+ `" b" ^
for(k = 0; k < max; k ++)
7 b+ b# c$ s2 i9 t
{
4 t# U" s+ r) r; A3 c' @% A
sum += input[i * max + k] * input[j * max + k];
- R- S9 s$ Q& u0 t
}
' w$ F' \7 P/ e
cover[i * max + j] = sum / max;
" r, l. a$ B: N3 n1 Y
}
3 {/ T" b6 B. C
}
0 o `9 k1 S8 G! ~% J4 ~, Q
实例,如input[16] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16},得出的cover如下:
3 Y9 R! f/ t+ r. C( `
7 17 27 37
' z1 p. N5 f/ u( Y1 F
17 43 69 95
( p. o7 Z2 y8 a. G3 q: _8 S
27 69 111 153
/ ]! `4 C9 _+ S1 M" D N# M% D1 t6 ` O
37 95 153 211
3 L6 O0 c, O9 A$ {
图示:
) C, O6 J$ j$ Z; }$ i
, T0 v8 S4 Y+ \
原理:只需要得到左上角或右上角即可,然后半个矩阵赋值给另半个矩阵即可得到整个矩阵。
) P" F7 W0 r% X% _* }, U
算法优化后:
$ `4 w( R8 m o. ~3 t Y$ p" e
for(i = 0; i < max; i ++)
. U. ^& W- S; F9 H+ \
{
6 o, h7 L, t1 K% I
for(j = i; j < max; j ++) // 减少一半循环
7 K+ X# ]+ N9 q
{
( u2 F. y' C7 S: W* ^4 {9 v
float sum = 0.0;
* Z% }2 C. w! h
for(k = 0; k < max; k ++)
9 L7 n- E% Q& {6 y$ f: Q: K
{
7 k: k+ m- U" z" W7 o `* u. H8 z
sum += input[i * max + k] * input[j * max + k];
& }- U7 ~( V% K0 g
}
% f+ y& G& d& C4 o
cover[i * max + j] = sum / max;
9 b' I6 l, _" C, F6 t
if(i != j) // 可加可不加,消除中线上的重复赋值
9 r) G8 r8 y1 v- N$ F
{
6 N( f; B) {. Z! S: f' t
cover[j *max + i] = sum / max; // 赋值给另半个矩阵
0 p9 e- _& { N1 \# X
}
7 }0 \8 S8 q0 M3 ]' B
}
: E( c) i' [0 V6 c, X2 c
}
' Q: g2 | ^1 C" H, ?% V
(2)条件跳转(使用条件跳转会在流水线中浪费更多的周期)
7 c, f0 n" S J$ [
k = k -1;
. t1 M# {0 y( F3 s+ O6 f
if(k < -1)
* U$ Z3 Q( ~3 D# A H/ \
{
0 ]2 b. }8 u+ X C
k = -1;
, D, ^4 q# ]' s" Q# w
}
. N8 S3 v7 V5 ~$ B" D; D; z
原理:C语言中的max函数在编译的过程中实际上实现的是DSP中的MAX指令。
7 |3 g4 g% r8 w) C4 D; K
优化后:
/ _: J5 c. A7 u! F
k = max(k-1, -1);
+ P! u0 r% w5 ]3 j1 l/ j9 b
转换成汇编后:
0 d$ G' t& e P" }# y* y
R0 += -1; // R0 == k;
0 q9 ?/ W- k1 Z7 [$ L
R1 = -1;
7 |' ^$ n) W( }% e: x. j
R0 = MAX(R0, R1);
1 c! @& N1 Q7 S4 ^! h
(3)for循环中的条件跳转
- ~+ t3 H! ~* Z4 g3 z
for
; t, J$ o, P8 R; C% p) w* d) h
{
6 v$ H1 `- ]7 N0 B* \
if{...}else{...}
% B( B; w6 n- @ Z2 @# x
}
4 i1 A1 r4 g; F& o! L. J' R3 E
原理:减少频繁的条件跳转,当然并不是所有的情况都可以这样做。
' \+ T8 K* k# }0 U- m, ]& M' _9 {
优化后:
3 K! v$ X) h5 ~: Y
if
) I/ F* M) Y v: i
{
7 c( m/ d( `7 e8 t% j( p
for{...}
/ ~0 G* v: r! J+ A$ C/ y7 h
}
9 V0 s$ c" S4 w3 H6 c; P
else
. @ u- E% f' h- A0 T1 [
{
1 O. v. H2 t0 E% o$ ]: p D, G
for{...}
: b& S* f1 o1 f! [* z9 I) p( i& u
}
5 r' v" ?5 N ~! l4 ?
(4)使用断言指令来避免条件跳转
4 P3 I. ?" |# y, p+ |1 l! @- U
if(A)
* Q3 y$ A" ~* L: e- x' O3 Z: V
{
, X8 b V/ |( e, P# r Q* V
X = exp1;
3 [- ~* V% O0 D7 j, p
}
% }! n, e! [: {/ |
else
% m& d* V( |! ?# `7 x1 M/ T- a* T
{
3 H* t% \8 c9 T4 s A. L
X = exp2;
. @4 ^7 z( F1 E: Q' g/ _9 A, K
}
" b+ t' C) ~ x5 t" [ E
原理:使用断言指令IF(CC) REG = REG,只会消耗一个周期。
+ k: \2 \1 v) b) {9 v1 l- L
优化后:
& g3 B6 ?3 i1 A5 h5 s" r
X = exp1;
/ B& q& r4 h# t: e8 E1 h- S
if(!A)
; a- r$ N. S6 ^4 V
{
% M' S$ j$ W1 N2 P
X = exp2;
# \' V, o9 i) o* r
}
: s4 |* N2 @6 N8 y
(5)除法(取模)操作
' ]! D8 m2 n5 j Y& ^% Z
一般DSP中不支持除法,除法操作是通过仿真的方式来进行实现,有两种,分为低精度和高精度,但都需要相大多的周期。
4 J1 P6 Z; R% o2 ^6 R m
除数为2的N次方时可采用右移法。
. y, r9 E8 p+ b! u* G* _; |* S
如为提高性能,可采取查表的方式,这样会损失精度。
6 r6 y& k. D+ L, Q* u+ f# e
隐藏的除法:
7 k/ H3 H3 }$ w& h8 B4 R" f/ H* Q
for(i = start; i < finish; i += step)
9 {7 j6 z' E- g x
此时编译器会looper = (finish - start) / step 得到次数。
" ~" L" `9 k% [' L% ^7 {
巧妙利用不等式法测:(不过可能会产生溢出,要小心使用)
) t; \! \0 |' O$ z
if(x / y > a / b)
; x/ H7 d" ^3 I5 W, X/ L
可转换为:
; I9 \. p! J6 C5 p% Y, P: y
if(x * b > a * y)
+ A8 G) ^0 U* L! O/ Y. f: P4 W# ?
(6)数据类型
7 ]& ?) R* Q7 q! s6 }" \% f+ b! k
对于定点DSP而言,对于浮点的操作是用仿真的方式实现的,会消耗很多周期,所以在定点DSP上对于浮点数一般是做定点化的处理,常用的方法我举一个例子:2.5 * a,其实可以转换成80 * a >> 5,不过在定点化时需要注意防溢出。
6 }. Y4 Y) a g$ f8 G0 @
对于64位数据,也是用仿真的方式实现的,会消耗很多周期。(一般最大仅支持32位数据)
$ Y3 x* A) s& W" X- ?8 \% {
做数字信号处理操作时,如FFT,16bit的操作是比较合适的。
# @$ r% y4 f1 I
要做控制类,条件跳转时,32bit的操作是比较合适的。
* g6 g1 Y; r/ G2 z/ A- O/ `6 T. T
如你的DSP的MAC是16位的,做乘法时,尽量定义成16bit数据。
8 _% @# {2 P9 S$ x) k1 k; m
(7)Memory分配
0 H0 j9 r# P! I8 t' w7 c; f0 s3 A
将运算比较频繁的数据和程序段放入片内Memory,开启cache。
& B$ N8 i2 l0 D8 f% o: K2 a
如DSP能对SDRAM的不同4个bank可以同时访问,此时你可以将需要同时运算的数据放入不同的bank
( w' ?9 Y$ q2 V0 N R
(8)开启仿真软件的编译优化选项
: ]! z5 a8 d' N! w5 Y4 j
在菜单相应的地方勾上即可,但值得注意时,开启自动编译优化选项后,可能会使执行的结果发生变化,所以需要测试对比一下未开编译优化选项之前的执行结果,一般来说,这个很方便,比较常用。
6 @ U0 S9 D* u1 @
以上8种是我常用到的优化方法,当然基于C层面算法类的优化还有很多种,这个需要慢慢积累,总结一下,一般来说先对C层面进行结构上的优化(上面的1-6均属于),然后进行Memory分配,开启仿真软件的编译优化选项,将运算频繁的程序段用汇编实现,当然如果性能满足要求,就没必要利用汇编了。
& Z: @; A b. L) I1 e; _
六、总结
+ _* @7 J g/ X4 J* `( q8 `- G3 X/ p
我认为学习DSP软件开发没有什么捷径,我花了大量的文字在“弄清DSP相关资源的来源及熟读手册”上,实际上是想说,懂得获取资源是很关键的,只有熟悉手册才能完全去使用你所要开发的DSP芯片,其次DSP的主要特点就是高性能,能做一些算法类的运算,所以DSP的优化是相当重要的,关于算法优化的方法有很多种,基本可分为C结构上的优化及利用DSP的特点来进行优化,优化的学习是日易积累的,所以就要多看看相关的资料了。
! r6 J L- J5 k) r9 k4 K3 x
快速入门的步骤如下:
0 `) v' U+ G4 q' j
准备一开发板,简单熟悉一下手册及仿真软件,对照着例程看手册,然后再改例程,看是否能按你的意愿去实现,最小系统和每个外设都熟悉一边,恭喜你,你入门了,待续。。。
作者:
ygcgsa
时间:
2016-5-16 13:51
楼主很用心啊!
0 l2 O. b t3 x0 [
感谢感谢!
作者:
zhoumi
时间:
2016-6-1 16:26
7 @* Z% C/ J0 ?! N2 R- T
haohao
作者:
cyxs
时间:
2016-6-2 15:28
谢谢O(∩_∩)O哈哈~谢谢O(∩_∩)O
欢迎光临 EDA365电子论坛网 (https://bbs.eda365.com/)
Powered by Discuz! X3.2