文章一、DSP学习心得

如果说前几年DSP作为一个器件,一个处理器或一个事物是相对比较新的东西,那么现在DSP已经在我们电子设计开发中非常常见了。首先我们从定义上简单理解一下DSP。我们涉及到的DSP主要是只这里特指数字信号处理器芯片,这里我把我的一些学习经验和大家分享。希望对大家有帮助

了解DSP
我个人认为学习一个东西首先是了解它,比如DSP到底是什么?用在什么地方?怎么用?和这里我们传统的单片机特点有那些相同与不同?开发需要注意什么?怎么样完成一个最小系统等。我想了解清楚这些问题我们自然就清楚比较清楚的认识DSP了。下面我们就来对上面的问题我们在很多地方都可以找到答案,我把其中比较重要的简单的回答一下。

DSP大家注意和传统的概念区分一下,传统我们经常说的DSP(Digital Signal Processing(数字信号处理))的缩写也就是说是一些功能算法,这里的DSP是指(Digital Signal Process(数字信号处理器))的缩写,也就是说他是一个集成一些外设的一个芯片,类似我们的单片机。我们通过程序实现一些特定的功能。

和传统单片机比较的区别?

DSP功能比普通单片机高出很多,当然价格也比较高。所以直接用DSP和单片机比较是不合适的。我们这里比较不是从他的应用领域来比较,我们是从开发的角度来比较,为了是使那些熟练使用单片机的朋友可以很快上手。当然我的主要目的的大家可以比较学习,达到。

熟悉一种CPU其他就可以很快上手。下面从几个方面比较一下

1,硬件上比较
从硬件上比较DSP和传统的单片机主要有几个方面不一样,很多DSP电源系统比传统的复杂,但是这个并不影响我们因为如TI的DSP都提供相关的测试电路。开始的时候大家可以完全按照他来设计。调试方式上有很大不同,DSP一般通过JTAG来进行仿真和烧写的,而单片机是通过直接仿真器来仿真的(这里讲的单片机是比较早的,现在的单片机也有很多采用JTAG调试方式)。其他设计比如重要的时序设计所以CPU系统是一样的只要满足时序就可以达到目标。

2,软件上比较
相比硬件软件应该是DSP差别比较大的DSP的软件需要CMD文件,一般的单片机编译器编译以后就可以了不需要。并且CMD也是DSP学习过程中比较困难的一个方面。后面我们简单说明一下。

构建DSP最小系统

小系统的是任何DSP系统开发前必须要完成的,你可以从一下几个方面获得小系统。一、购买一个市场上比较成熟的小系统产品;二、自己动手设计一个小系统。我们这里主要告诉大家怎么自己设计一个最小系统。

首先我给最小系统一个定义,我按照我个人的习惯把最小系统分成2个方面

1.狭义的最小系统

所谓狭义最小系统是指就是能够完成一个独立功能,并且方便观察的一个系统。比如我们常见的通过DSP控制一个LCD灯让它闪起来。完成这个功能我们可以认为狭义的最小系统完成。独立完成功能,我们很容易想到要一个系统能够独立完成功能必须需要的部分应该有电源电路、时钟电路、复位电路。这个和我们单片机基本一样只是在电路设计上注意看手册这个会少出错。其实对于一些DSP来说光是这样是不够的,我们必须要有存储器系统,如果是采用2000系统可以不需要扩展因为他内部自己有FLASH,但是对于5000系统来说就必须扩展非易失性的FLASH等存储器保证系统在掉电重新上电后可以正常工作,所以除了考虑通用单片机的3个方面我们还需要在存储器,BOOTLOADER方面了解DSP,这个也正是大家学习DSP比较困难的地方。

方便观察这个是我自己增加的一个方面,主要是让大家养成良好的习惯,比如我们在设计系统时加一个LED或者蜂鸣器这样在调试的时候会给我们带来很多好处。比如我们设计一个IO操作的程序通过IO输出一个方波,我们可以通过很多方法来观察我们的结果是对好是错。我们可以通过示波器,但是由于很多初学者不一定具备这个条件。如果我们有LED就可以通过他的状态来观察程序运行的结果.

2.广义的最小系统

广义的最小系统除了具有上面狭义最小系统的功能外还必须具有一个功能可开展性。这个在系统设计中是非常重要的。如果说我们可以设计并完成一个狭义的最小系统就代表我们对DSP已经入门了。那么完成可扩展性功能就代表你可以使用DSP进行系统设计了。

可扩展性在这里我要主要讲的是时序,也就是我们设计的时候必须满足他的时序功能。经常在论坛里面看到大家问我的系统怎么扩展一个存储器或者其他外设。即使有一些参考电路我们怎么判断他的正确与否。这一点正好和我们的单片机系统重合。所以我常常说知道一个CPU怎么用要用一个新的就非常简单了。下面我们就谈谈时序设计需要注意的地方。

一、首先要熟悉主CPU的时序,也就是说你需要向外设写或者读取一个数据你是采用什么方法的。比如我们的DSP系统的数据手册就专门有一大段内容对外部程序空间、数据空间、IO空间访问的图和说明。

二、熟悉我们外设对时序的要求,这个很容易理解,你打算读写我总应该知道按照什么样的方法怎么读写吧。一般在手册上也是很清楚的。

三、当我们清楚DSP和外设的时序后我们来判断他们是不是匹配(简单点说就是可不可以实现数据的读写功能)如匹配电路设计就是正常的否则我们要想办法让他们匹配。其实这个过程就是电路设计和判断的过程。

关于时序的设计的详细说明几句话说不清楚我们可以在论坛上来一起讨论他是我们数字系统设计的核心。

四、软件最小系统,很多朋友在论坛上说没有一个具体的思路来写DSP程序或者直接是看不懂人家的。其实这些多少没有系统概念造成的。如果我们知道软件最小系统有那几个文件组成。他们主要完成什么功能我们在一个一个的理解和消化他这样不就可以很好的写出程序。比如我们DSP的一个软件系统主要有头文件、库函数、中断向量表、存储器分配文件(CMD)

复杂的CMD文件

CMD文件是DSP学习中初学者遇到的最大的问题,这里我简单说明一下CMD下面是一个2407程序的CMD文件

MEMORY
{
  PAGE 0:    /* Program Memory */
    VECS:           org=0000h,   len=00040h   /* internal FLASH */
    FLASH:          org=0100h,   len=7fffh   /* internal FLASH */
  PAGE 1:    /* Data Memory */
    B2:             org=00060h,   len=00020h   /* internal DARAM */
    B0:             org=00200h,   len=00100h   /* internal DARAM */
    B1:             org=00300h,   len=00100h   /* internal DARAM */
    SARAMDATA:      org=00800h,   len=00800h   /* internal SARAM */
    EXTDATA:        org=08000h,   len=08000h   /* external SRAM  */
}
SECTIONS
{
/* Sections generated by the C-compiler */
       .text:   >  FLASH    PAGE 0   /* initialized */
       .cinit:  > FLASH     PAGE 0       /* initialized */
       .const:  > B0        PAGE 1    /* initialized */
       .switch: > FLASH     PAGE 0   /* initialized */
     .bss:    >  EXTDATA        PAGE 1
       .stack:  > SARAMDATA PAGE 1      /* uninitialized */
       .sysmem: > B0        PAGE 1   /* uninitialized */

/* Sections declared by the user */
       .vector:  >VECS      PAGE 0   /* initialized */
}

CMD文件应该首先清楚他的作用,它是用来把DSP的段进行管理的文件。简单的说就是把一段放在什么地方。

CMD的结构主要分成2个大的方面,

1、MEMORY他的主要作用是系统存储器声明也就是说用来描述硬件系统存储器有多少分别在什么地址范围,这样就告诉我们在写MEMORY的时候必须和硬件结合起来。我归纳的原则的对于硬件系统有的存储器在声明的时候不全声明,但是对于物理硬件上没有的存储器一定不能在里面声名。因为这个声明的存储器是为了存放数据准备的,你不存在当然不能声名。

SECTION指令是把相关的段放在存储器的一个位置。大家可以看DSP怎么按照段管理的就很清楚了。特别注意一下中断向量段。

学习应该学会总结和比较

回顾自己使用多种CPU和DSP到现在我觉得最重要的是在学习过程中总结一下自己的得与失。这样才有比较好的进步。
比如我们前面讲到是DSP和单片机的相同与不同点我们只要熟悉单片机并且清楚相同与不同点,我们就知道从那些方面下手这样学习的效率就会提高。
由于我在这方面知识结构的欠缺希望错误和不足的地方大家多多指正。

文章二、DSP学习的三个阶段
同济研究生期间断断续续做过TI DSP研究,从一个对嵌入式一点也没有了解的新手到快毕业时完成一个自认为满意的项目,其中走过很多弯路,现在把我对DSP学习的心得和一些参考文献列出来,可能对初学者具有帮助。

实验室用的是一款闻亭的DM642开发板,当时这款开发板还比较新,国内中文资料很少,而且闻亭但是的例子程序均是采用TI的原程序,不像合众达的例子程序容易上手,所以可能合众达的板子比较适合初学者使用。

DM642是一款针对图像应用的高端DSP,近几年来国内应用的范围很广。对于DSP软件学习而言个人认为包含了3个方面的东西:1:芯片的外设,对芯片的基本操作和简单程序运行环境。2:嵌入失操作系统原理(DSP/BIOS)。3:DSP算法的移植和优化工作。下面分别对这三个方面做论述。

1.芯片的外设,对芯片的基本操作和简单程序运行

学习DSP 首先是要对芯片和你所用到的芯片外设的数据手册说明比较清楚,对于初学者可能在刚开始看datasheet时感觉很头晕,因为datasheet只是一些说明性的东西,他没有教你怎么去用,所以datasheet部分一定要结合相应的例子程序去看。对于芯片的外设操作TI提供了一个CSL的函数,帮你事先定义好了一些寄存器地址,这样就不用你去查找每个寄存器的详细地址。

现在的C6000 程序开发大部分采用C语言,极少数的关键代码采用线性汇编或者汇编语言。对于一个C语言运行工程需要的最少元素是:1:main函数 2:cmd文件3:runtime support lib。这是让一个基于C语言的工程跑起来的最少条件。换句话说只要有了这三个东西我们就可以在DSP上做任何想做的事,但是考虑到做大型工程和复杂应用的需要,通常又要用到操作系统DSP/BIOS和驱动。

在阶段首先是让一个最简单的hell world工程跑起来,这个工程这包含三个文件,一个main.c一个CMD文件,一个 rts.lib。然后在查数据手册DSP的外设资源调试一遍,这个过程完成后几基本上手了:)。

在这个过程中需要搞明白的是一个过程,三个文件,和简单的调试方法。一个过程是C语言怎么生成.out可执行文件的过程,通常包含编译,汇编,连接三个过程。几个文件是obj, cmd, map,文件Obj,Cmd和Map文件的格式在TI的CCS 文挡帮助中都有详细论述。调试方面我们可可以利用防真器可以让程序在任何地方停下来,然后利用CCS的Memory View功能可以查看想要知道的CPU地址映射的区域。

这部分的参考资料可以查看
(1)电子科技大学出版的 C/C++语言硬件程序设计--基于TMS320C5000系列DSP
(2)帮助文档

2.嵌入失操作系统原理(DSP/BIOS)

这部分就有嵌入式操作系统知识了,DSP/BIOS是不开源的,如果想对操作系统的知识了解深入的话可以看看uc/os-II的原代码。嵌入式操作系统的基本原理都一样。这个完成后在把Ti关于DSP/BISO的列子程序跑一便熟悉操作系统中各个模块,如TSK, TIMER…..。

在熟悉完操作系统后,剩下的就是对DSP/BISO的驱动模型了,TI 的驱动模型采用的是class-mini driver模式,其中class driver就是一些函数接口,提供到mini driver的访问。其中mini driver实现方式根据不同的板子和芯片会不一样,建议选取一个外设资源,看懂其源代码,这些代码一般都在几个c 文件内,其中最主要是5-7个函数的实现;
mdBindDev()
mdUnBindDev()
mdControlChan();
………………….
DSP/BIOS的驱动比较简单,总得来说驱动可以分为2个部分,一部分函数硬件的初始化和控制工作,这部分相对交简单;另外一部分函数负责 I/O,buffer的同步工作,这部分通常要复杂的多,而且这部分函数常常和中断牵涉在一起,所以在看驱动源代码时一定要时刻知道中断什么时候发生,中断服务函数里面做了些什么,对其他函数的影响是什么等。如果能把驱动代码看一遍对于C语言提高是很大的。

这部分的参考资料可以查看
(1) DSP/BIOS user guide
(2) How to write DSP device driver
(3) 嵌入式实时操作系统UC/OS-II

3.DSP算法的移植和优化工作

这部分是最后工作,一般也是比较耗时间的工作。现在如果实现比较复杂的系统不做DSP程序的优化是肯定不行的。DSP程序的优化方法有很多,网上也有很多资料,但是以我实际的经验来看很多人都没有把握关键的地方,如果是复杂算法的话DSP优化的第一步应该是存储器优化,也就是说利用ping-pong buffer技术将待处理的数据分批的搬运到片内存储器中,在这个工程中要结合片内资源,设计好数据结构,并一定要考虑让数据对齐。存储器优化是 program optimization 文档中没有提及,而是在一个叫Cache user guide 文档中说明,所以这样就造成很多人不知道原因。在完成存储器优化之后就是program optimization 文档中所讲的方法,-o3,数据打包,inline,循环展开,汇编等等。
做优化的过程中一定要保证优化之前和之后的处理结果正确性,也就是说优化不能导致错误的发生,然后在尽量提高时间。

关于优化后函数运行时间的测量TI的有个文档里面有教你怎么测,就是利用定时器来测量函数运行的时间,另外对于运行时间本来就只有几百个cycle的短小汇编函数也可以利用CCS 的clock功能来测时间。

总之程序优化就是一项耗时间的体力活,哈哈!

这部分的参考资料可以查看
(1) program optimization guide
(2) cache user guide