前言
在上一篇文章中,我们介绍了一些关于直接记忆体存取(DMA)的基础,例如其必要性、架构以及如何控制等。在本文中,我们将会集中在DMA移转的分类上,以及关于分类在设定上的概念。
设定DMA
DMA移转设定有两种主要的类型:暂存器模式(Register Mode)以及描述符模式(Descriptor Mode)。而不论是何种类型的DMA,(表一)中所描述的相同类型资讯,都会进入到DMA控制器中。当DMA以暂存器模式运作时,DMA控制器只会使用存在于暂存器中的数值。而当DMA以描述符模式运作时,DMA控制器则会在记忆体中搜寻其设定用数值。
(表一) DMA暂存器
Next Descriptor Pointer (lower 16 bits) |
Address of next descriptor |
Next Descriptor Pointer (uper 16 bits) |
Address of next descriptor |
Start Address (lower 16 bits) |
Start address (source or destination) |
Start Address (uper 16 bits) |
Start address (source or destination) |
DMA Configuration |
Control information (enable, interrupts, 1D vs. 2D) |
X_Count |
Number of transfers of inner loop |
X_Modify |
Number of bytes between each transfer in inner loop |
Y_Count |
Number of transfers in outer loop |
Y_Modify |
Number of bytes between end of inner loop and start of outer loop |
以暂存器为基础的DMA
在以暂存器为基础的DMA中,处理器会对DMA控制暂存器直接进行编程,以便启始移转作业。以暂存器为基础的DMA,具有最佳的DMA控制器性能,这是因为暂存器不需要从记忆体中的描述符持续地重新读取资料,此外核心也不需要去对描述符进行维护。
以暂存器为基础的DMA包含有两个次模式(sub-mode):自动缓冲模式(Auto-buffer Mode)以及停止模式(Stop Mode)。在自动缓冲DMA中,当一个移转区块完成时,控制暂存器就会自动的重新读取其原始设定数值,然后相同的DMA程序就会重新开始,而不会有任何多余的开支。
如(图一)所示,假如我们设定了一组自动缓冲DMA,要将某些数量的字元,从周边移转至L1资料记忆体中的缓冲区内,DMA控制器会在前一个字元的移转完成时,立即重新读取初始参数。这将会形成循环缓冲(circular buffer),因为当数值被写入缓冲区内的最后一个位置之后,下一组数值就会被写入缓冲区内的第一个位置。
对于性能相当敏感,具有连续资料串流的应用来说,自动缓冲DMA特别适合。 DMA控制器能够独立读取串流资料,不会受到处理器动作的影响,并且当每个移转完成之后,可对核心发出中断要求。虽然想要很平顺的将自动缓冲模式停止下来是可能的,但假如一组DMA程序必须要经常性的启动与停止,那么使用这种模式就不恰当。
以下我们来看一个自动缓冲的范例。
自动缓冲的范例:双重缓冲
假设有个应用装置,其处理器是以每次512笔音讯取样的方式运作,而其编解码器(音讯类比 / 数位转换器)则是以音讯的时脉速率来传送新的资料。在这样的一个架构中,自动缓冲DMA可以算是最佳选择,这是因为资料的移转会在周期性的间隔内发生。
双重缓冲
以此相同的模型来作为基础,假设我们想要将所接收到的音讯资料进行双重缓冲(double - buffer)处理。也就是说,我们希望当一组缓冲区正在运作时,DMA控制器可以将另一组缓冲区填满。处理器必须在DMA控制器将特定资料缓冲区的启始部分包围起来之前,先在该缓冲区上将工作完成,如(图二)中所示。使用自动缓冲模式的话,设定就会很简单。
缓冲组计算方式
自动缓冲DMA的总数量,必须要透过一组2D DMA,来将两组资料缓冲区的大小包含在内。在这个范例中,每个资料缓冲区的大小与2D DMA中内部回路的大小相当。缓冲区的数量则与外部回路相当。因此,我们将维持 XCOUNT = 512。假设音讯资料元素的大小是4 位元组,我们将字元移转大小编程为32位元,并且设定XMODIFY = 4。由于我们需要两组缓冲区,因此我们设定YCOUNT = 2。假如我们希望这两组缓冲区在记忆体中是back-to-back的话,那么我们必须设定YMODIFY = 1。然而,将缓冲区个别分开,通常会是比较明智的作法。此种方式可以让你避免掉当处理器与DMA控制器在对相同的记忆体副插槽(subbank)进行存取时,两者之间所产生的冲突。要达成这样的结果,可以将YMODIFY提高,以便在缓冲区之间提供适当的区隔。
在2D DMA移转中,当XCOUNT抑或是YCOUNT到期时,我们还有产生中断的选项可供选择。将其转移到这个范例中时,那就是我们可以设定每当XCOUNT降为0、亦即每组512移转结束时,DMA中断就会被触发。若我们将其想像成当每个内部回路终止时、所接收到的中断,就能比较容易理解。
停止模式的运作方式
停止模式的运作方式与自动缓冲DMA大致相同,除了在DMA完成之后,暂存器不会重新读取,因此整个DMA移转只会运行一次而已。对于会针对某些特定事件而触发一次性的移转而言,举例来说,以非周期性的方式将资料区块从一个位置搬移至另一个位置,停止模式是最为有用的方法。当需要让事件同步时,这个模式也相当的有用。举例来说,假如有一项作业必须要在下一个移转启始之前完成,使用停止模式可以确保这个流程的正确性。此外,停止模式对于缓冲区的初始化也是相当有用。
描述符模式
以描述符为基础的DMA移转,需要一组储存在记忆体中的参数,以便启动DMA序列。描述符中所包含的,是所有通常会被编程并写入DMA控制暂存器组的相同参数。然而,描述符也允许多重的DMA序列相互链结在一起。在以描述符为基础的DMA运作下,我们可以将DMA通道予以编程,以便自动进行设定,并且在现有的序列完成之后启动另一组DMA移转作业。在对系统的DMA移转做管理时,以描述符为基础的模型能够提供最大的弹性。
描述符模型:以ADI为例
在ADI的Blackfin处理器中有两种主要的描述符模型 ,一种是「描述符阵列」,一种是「描述符清单」。具有这两种模型的目的,是为了可以在弹性与性能之间取得平衡。
在描述符阵列模式中,描述符会常驻在连续记忆体之中。 DMA控制器仍然会从记忆体内读取描述符,但是因为下一个描述符,会紧接着现有的描述符,因此两个用来记录寻找下一个描述符、以及它们所对应的描述符读取字元,也就不再重要。由于描述符并不包含此一「下一描述符指标」(Next Descriptor Pointer)资料,DMA控制器就会认为记忆体中的这些描述符群组,会如同阵列一般地一个接着一个排下去。
使用描述清单
当个别的描述符,在记忆体中不是以back-to back的方式配置时,就可以使用描述符清单的方法。事实上有许多种类的次模式可供使用,以便在性能与弹性之间取得平衡。在「小型描述符」(small descriptor)的模型中,描述符包含一组单一的16位元场域,该场域是用来作为「下一描述符指标」场域较低部分的设定所用;较高部分则会透过暂存器个别加以编程,并且不会改变。当然,这将会使描述符被限制在记忆体内的特定 64K ( =216 )分页(page)内。当描述符的位置超出这个界限之外时,就要使用能够提供32位元作为「下一描述指标」资料的「大型」模型。
描述符读取
不论采用何种描述符模式,使用越多的描述符数值,都会需要越多的描述符读取。这就是为何Blackfin处理器要指定一组「弹性描述符模型」(flex descriptor mode)。该模型可以适当调整描述符的长度,使其只包含只有针对特定移转所需的资料,如(图三)所示。举例来说,假如 2D DMA没有需要的话,YMODIFY以及YCOUNT暂存器就没有必要成为描述符区块中的一部份。
描述符的管理
要回答管理描述符清单的最佳方法,此一答案必须视应用领域而定,不过最重要的是要了解有什么样的选择可用。
链结
首先我们将要讨论的选项,其运作模式与自动缓冲DMA非常相似。在这个选项中,必须要对链结在一起的多重描述符进行设定,如(图四a)中所示。
「链结」(chained)意指前一个描述符会指向下一个描述符,同时也会自动读取。想要完成这个链结,最后的描述符指标,必须指回到第一个描述符,重复运作处理程式。使用这项技术而不利用自动缓冲模式的原因之一,就是在移转的大小与方向上,使用描述符会具有较多的弹性。
致能
其次我们讨论的选项,则是以处理器手动管理描述符清单。描述符实际上是属于记忆体内的架构。每个描述符包含有一个设定字元,而每个设定字元则包含有一组「致能」(Enable)位元;当一组移转启动时,此位元可作为调整之用。现在我们假设有4组缓冲区、必须要在某些特定的作业区间内搬移资料,假如我们所需要的是,当处理器准备妥当时,就让处理器分别启动每个移转作业,那么我们可以预先设定好所有的描述符,不过其中的「致能」位元必须予以清除。当处理器判定启动描述符的时间已到时,它将只会更新记忆体中的描述符,然后写入DMA暂存器中,以便启动各自分隔开的DMA通道。 (图四b)所示为这套流程的范例。
串流同步化实例操作
这种类型的移转何时才会派上用场?试想有个多媒体应用装置需要将输入串流与输出串流同步化。举例来说,即使工程师尝试要将这些串流调整成相同的时脉速率,视讯取样接收至记忆体的速率、与所播放的输出视讯速率之间,可能是不相同的。在同步化是个问题的大前提下,处理器可以针对与输出缓冲区相关连的DMA描述符,进行手动调节。在下一组描述符被「致能」之前,处理器可以透过确保一次只有一个实体(entity)在对共用资源做存取的信号机制(semaphore mechanism),来调整现有的输出描述符,以便将串流同步化。
在处理器之间使用内部的DMA描述符链结、或是以DMA为基础的串流时,如果在所传送资料区块的末尾加上一个额外的字元,其中包含如何处理资料、同时可能包含时间戳记(time stamp),也是相当有用,该字元对于判定封包是否已被传送出去,则有所帮助。 (图4b)中以虚线所标示的区域,就是这种架构的范例。
软体为核心的DMA功能
在最复杂的应用领域中,会具有以软体做成的DMA管理员功能。这项功能可能会成为作业系统或即时核心的一部份,但是它也可以不需要依赖这些而自行运作。在Blackfin处理器中,这项功能是以VisualDSP++工具套件中系统服务的一部份为基础。这项管理功能让工程师能够透过标准的应用程式介面(API)来搬移资料,而不需去对每个控制暂存器进行手动设定。
基本上,应用会提交DMA描述符的请求给DMA伫列管理员,而其职责就是处理每个请求。这些请求会依据被应用软体所接收到的顺序而加以处理。通常,一个指向「回覆」(call - back)功能的位址指标(address pointer),也会是系统的一部份。当一组资料缓冲区已经就绪时,这项功能会完成你希望处理器所要执行的作业,而无需让核心滞留在高优先权的中断服务常式内。总而言之,由于DMA管理员抽象化资料移转过程,因而能简化编程模型。
管理描述符伫列
想要使用中断来管理描述符伫列,通常有两种方法。第一种是以每组描述符完成时的中断为基础,只有当工程师可以确定每个中断事件都能个别地被处理,不会有中断溢出(overrun)时,才能使用这种方法。第二种方法所牵涉到的中断,是只有当一组工作区块(work block)的最后一个描述符所指定的移转作业完成时,才会产生。一组工作区块乃是一或数个描述符的集合。
想要保持描述符伫列的同步化,非中断软体必须要维持计数加入到伫列中的描述符,而中断常式则会维持计数从伫列中移出之已完成的描述符。只有当DMA通道在已处理完所有的描述符之后而暂停下来时,其数量才会相等。
小结
在这篇文章中,我们主要讨论是以暂存器和描述符为基础的DMA资料流结构,以及何时该使用哪种类型。下一次我们将会讨论一些能够在多媒体系统中,提供协助并使得资料搬移更为有效率的先进DMA特点。 (本文由ADI美商亚德诺提供)