|
如果通过I2C总线对DSP实现引导装载,对存储数据的I2C设备有如果几点要求:
(1)该设备首先必须兼容Philips的I2C总线规范V2.1,工作在从设备模式,并且其从设备地址为0x50。
(2)设备内部使用两个字节寻址,即在接收到主机写命令后,其后接收到的数据是16位的地址数据。
(3)对设备读取时,相关设备必须支持自动寻址增量,即每读一次,其内部地址指针自增1,保证程序按顺序读出。
常用的I2C接口E2ROM有ST公司的M24系列及Philips的PCF85系列的E2ROM,根据程序大小选择相应的芯片,需要注意的是I2C引导模式最多支持64kB的数据。
在I2C引导模式运行时,DSP作为主设备来控制I2C总线的时钟,对于DSP来说,SCL必须满足根据方程(1)所得到的速率,而I2C引导模式支持的最高时钟速率为400kHz,所以如果想利用I2C引导模式,DSP上电时输入时钟就不能大于12MHz。
SCL(高)=SCL(低)=15×(DSP输入时钟周期) (1)
2.2 I2C引导模式数据存储方式
为了能正确地将数据从外部存储器搬移至DSP内部,用户程序需要将数据按照一定格式存储在E2ROM中,按照这些格式存储的数据便是自举表(Boot table),自举表是Bootloader程序能正常运行的保证,只有将数据按照自举表的要求存储,用户程序才能被搬移到DSP内部正常运行,在自举表中除了用户数据外还需要一些Bootloader控制数据,如程序入口地址(entry point address)、寄存器配置(register configurations)和可编程延迟(programmable delay)等,自举表的结构如图2所示。
其中程序入口地址在将用户程序搬移至DSP内部后,用户程序从该地址处开始运行,通常情况是中断向量表的reset处,在Bootloader搬移数据之前,如果需要可以改变某些寄存器的值,如DSP的clock配置寄存器、EMIF配置等,通过自举表配置这些寄存器后,需要一定时间才能正常工作,否则会导致引导程序失败。延迟计数器是让Bootloader推迟相应的CPU周期再进行数据搬移,确保引导程序正常工作,由于DSP是采用分段格式来组织数据的,如代码段、数据段和用户自定义数据段等,所以生成的自举表也是按照对应格式来建立的分段存储,这样有利于程序维护,实现模块化设计。
在自举表的最后,是连续的4个字节的全零数据,其目的是为了告诉DSP程序引导完成,可以传至程序入口执行,同时DSP也发出指示给外部存储设备告知引导结束,在I2C模式中,作为主机接收设备的DSP信号将会在接收到结束标志后在数据总线上给出停止标志,用来结束数据传输。
要建立自举表,可以利用TI提供的HEX转换程序(HEX55.exe),将生成的连接文件转换成用于存储器的数据格式[1]。首先,需要建立一个CMD(链接命令文件linker command file)文件,输入需要的链接选项,HEX55利用该文件提供的各种选项来转换文件,下面是一个为I2C引导方式建立的CMD文件和其选项以及具体含义:
通常情况下还需定义采用某种方式如-Serial8、-parallel16等选项,表示采用何种Boot方式从而生成对应的存储格式,由于采用了I2C模式来引导,所以这些选项可以不使用,另外还可以使用-reg_config和-delay选项,分别来设置需要改变的寄存器值以及需要延迟的CPU周期数,最后需要注意的是HEX55程序要使用v2.1及后续版本,早期版本生成的自举表不能正确引导程序。
3 ARM端设计
上面介绍了利用I2C接口的E2ROM来实现引导装载的硬件连接和需要的数据存储形式,实际利用ARM自身的I2C控制器,将自举表存储在ARM的FLASH中,并且让ARM按照I2C引导模式中E2ROM的时序向DSP发送对应的数据,实现对DSP的引导装载,所选用的ARM是Philips的LPC2138。LPC2813是基于32b ARM7的内核,内部拥有多达512k的高速FLash和32k的静态RAM,其工作频率可达60MHz,其I2C总线控制器支持I2C所有工作模式,这些在用于引导DSP时就不用使用端口来模拟I2C时序,使用十分方便,引导DSP时,只要ARM按照对应的顺序来发送数据,就能实现DSP的程序引导,使用ARM引导时,只需将图1中的SCL和SDA分别与ARM的SCL和SDA连接即可。
Bootloader使用I2C读取数据时其时序如图2所示。引导开始后,DSP首先会使用随机读取指令(random read command)从0x0000地址处读取数据,该读取指令由一个虚假的写指令和当前地址读取指令(current address read command)组成,ARM正确响应该指令后,DSP便继续采用当前地址读取指令读取剩余数据。
在LPC2138中,I2C总线有专门的控制器,并且每次接收到数据后对应的I2C状态寄存器会以不同的代码来表示当前I2C总线状态,用户可以根据不同的状态来进行下一步的操作[3],整个引导过程就是ARM根据不同的总线状态来发送或接收相应的数据,使用ARM引导DSP程序加载时,ARM作为从设备工作,在两种工作模式之间切换,分别为从设备接收(slave receiver和从设备传输(slave transmitter)。
下面介绍ARM端程序的运行状况,程序中首先通过I2C地址寄存器(I2ADDR)将ARM的从设备地址置为0x50,再利用I2C置位控制寄存器(I2CONSET)将其中的I2EN和AA置1,这样ARM就工作在从设备模式,一旦I2C总线接收到有效数据,程序就进入到中断服务程序中运行,用户程序根据I2C状态寄存器(I2STAT)的值判断当前状态从而进入下一步操作,图3为中断服务程序工作流程。
图3中State代表接收到数据后,I2C状态寄存器中的值,不同的值代表总线上可能出现的各种状态。0xA0代表程序收到的是start或是stop标志,返回主程序继续等待中断,0x60代表接收到自己的从设备地址和写命令,并返回ACK信号,Count1代表收到的写命令次数,由于整个引导过程中只能接收到一次写命令,所以只要Count大于1则接收出错,需要重新启动引导程序,利用ARM控制DSP的复位信号重新开始引导过程,直至成功引导,0x80表示ARM进入了从设备接收数据状态,并且前边已经收到了本机的设备地址,此次接收到了数据并返回ACK信号,I2DAT在从设备接收模式时存储接收到的数据,发送模式时存储待传输的数据,引导开始后,连续两次接收的数据应该为0,若并不为0,表示引导程序出错,需要复位DSP重新开始接收。
Count为连续两次接收数据0的计数器,一旦满足条件,将发送缓冲区的首地址取出存储在Trans_addr中,0xA8代表接收到当前地址读取命令,一旦接收到此命令,将待发送数据取出送入发送数据寄存器I2DAT,以便下一次传输时将数据送出,0xC0表示数据发送成功,而且没有收到ACK信号,意味着当前地址读取命令结束,此时将发送缓冲区地址加1,取出下一次待发送数据地址,这样便完成了1个字节数据的发送,整个引导过程一直到DSP收到自举表结束标志后停止,需要注意的是,I2C中断标志位需要通过软件清除,每次中断返回时都必须用I2C清零控制寄存器(I2CONCLR)手动清除I2C控制寄存器中的中断标志。
按照上述方法就完成了I2C引导装载模式,用户可以在程序中加入测试程序,通过控制GPIO高低变化生成脉冲,利用示波器观察从而判断程序引导是否成功。
4 结语
本文提出的引导方式已经成功地应用于一款低功耗、小型户数传设备当中,免去了对外部存储器的编程,特别有利于设备的升级和维护。