printf (“time in func2 = %u ticks\\n”, (unsigned int) (time3 – time2));
printf (“Number of ticks per second = %u\\n”, (unsigned int)alt_timestamp_freq()); }
return 0; }
6.5.9 使用 flash 设备
HAL提供对非易失性flash存储器设备的通用模型支持。Flash存储器使用特殊的编程协议来存储数据。HAL API提供写数据到flash的函数。例如,用户可以使用这些函数实现基于flash的文件子系统。 HAL API也提供读flash的函数,尽管通常不是必须的。对大多数flash设备,当对其进行 读操作时,程序将flash存储器空间看成简单的存储器,不需要调用特殊的HAL API函数。如果flash设备具有特殊的读数据的协议,如Altera EPCS串行配置设备,用户必须使用HAL API进行读写数据。 下面介绍flash设备模型的HAL API。下面的两个API提供不同的层次flash访问。
简单flash访问—函数写缓冲器数据到flash和从flash读数据都是以分区(block)的层次。 在写数据时,如果缓冲器比一个完整的分区小的话,这些函数擦除原来存在于flash中的在新写入的数据之上和之下的数据。 精细flash访问—函数写数据到flash和从flash读数据都是以缓冲器的层次。在写数据到 flash时,如果缓冲器比完整的分区小,这些函数会保留之前的存在于flash之中的在新写 入的数据之上和之下的数据。这个功能通常在管理文件子系统时需要。访问flash设备的API函数定义sys/alt_flash.h。 简单Flash访问
该接口包含函数:alt_flash_open_dev()、alt_write_flash()、
alt_read_flash()和 alt_flash_close_dev()。用户调用alt_flash_open_dev()函数来打开一个flash设备,该函数返回一个 flash设备的文件句柄。该函数需要一个单独的变量,就是flash设备的名字,设备名在system.h中定义。当获得了句柄,用户可以使用 alt_write_flash()函数写数据到flash设备。原型为:
int alt_write_flash(alt_flash_fd* fd, int offset,
const void* src_addr, int length )
调用该函数,写数据到由句柄fd标识的flash设备。驱动程序写数据从flash设备的基地址偏移offset开始。 写入的数据来自src_addr指向的地址, 写入的数据量为length。 alt_read_flash() 函数用来从flash设备读数据。原型为:
int alt_read_flash( alt_flash_fd* fd, int offset,
void* dest_addr, int length )
调用alt_read_flash()从fd标识的flash设备读数据,地址为flash的基地址偏移offset。该函 数写数据到dest_addr指向的地址,数据量为length。对大多数flash设备,用户访问时可以按照标准的存储器进行,不必要使用 alt_read_flash()。函数alt_flash_close_dev()需要一个文件句柄来关闭设备。函数的原型为:void alt_flash_close_dev(alt_flash_fd* fd ) 下面的代码显示简单flashAPI函数的使用,访问的flash设备名为/dev/ext_flash,在 system.h中定义。 例:使用简单Flash API函数 #include
#include
#include “sys/alt_flash.h” #define BUF_SIZE 1024 int main () {
alt_flash_fd* fd; int ret_code;
char source[BUF_SIZE]; char dest[BUF_SIZE];
/* Initialize the source buffer to all 0xAA */ memset(source, 0xAA, BUF_SIZE);
fd = alt_flash_open_dev(“/dev/ext_flash”); if (fd!=NULL) {
ret_code = alt_write_flash(fd, 0, source, BUF_SIZE); if (ret_code==0) {
ret_code = alt_read_flash(fd, 0, dest, BUF_SIZE); if (ret_code==0) { /*
* Success.
* At this point, the flash is all 0xAA and we * should have read that all back into dest */
} }
alt_flash_close_dev(fd); } else {
printf(“Can’t open flash device\\n”); }
return 0; }
擦除分区
通常,flash存储器被分成许多分区(block)。alt_write_flash()函数在写数据之前,可能 需要先擦除一个分区的内容。 这种情况下, 该函数不做任何保留分区中已存在的内容的工作, 这将导致不期望的数据擦除。 如果用户希望保持已有的flash存储器内容, 使用精细flash函数。 精细Flash访问
精细flash访问的函数对写flash的内容提供完全的控制。alt_get_flash_info()、 alt_erase_flash_block()和alt_write_flash_block()。从flash存储器的本质上来说,用户不能擦除 一个分区中单独的一个地址。用户一次必须擦除整个分区。因此要改变一个分区内特定的位置的内容,而不改变分区内其它位置的内容,用户必须先读出分区的整个 内容到缓冲器中, 在其中改变相应的内容, 擦除flash分区, 最后, 将整个分区内容写回到flash存储器。 精细flash 访问函数自动化上述的过程。 alt_get_flash_info()函数获得擦除区域的数目,每个区域内分区的数目,每个分区的大小。函 数原型为:
int alt_get_flash_info( alt_flash_fd* fd, flash_region** info, int* number_of_regions) 如果函数调用成功,返回number_of_regions指向的地址,包含有flash存储器中擦除区域 的数目,*info指向flash_region结构的数组。数组是文件描述符的一部分。
flash_region结构在sys/alt_flash_types.h中定义,其类型定义为: typedef struct flash_region {
int offset; /* Offset of this region from start of the flash */ int region_size; /* Size of this erase region */
int number_of_blocks; /* Number of blocks in this region */ int block_size; /* Size of each block in this erase region */ }flash_region;
调用alt_get_flash_info()获得的信息,用户能够擦除或编程flash中的单个分区。
alt_erase_flash()函数擦除flash中一个单独的分区。其原型为: int alt_erase_flash_block( alt_flash_fd* fd, int offset, int length)
flash存储器由句柄fd标识,分区由相对于flash的起始地址的offset标识,分区的大小通过 length传递。
alt_write_flash_block()函数写flash存储器中一个单独的分区。其原型为:
int alt_write_flash_block( alt_flash_fd* fd, int block_offset, int data_offset, const void *data, int length)
该函数写由句柄fd标识的flash存储器,写数据到相对于flash基地址偏移block_offset处,该函数写由data指向的位置起始length长度的字节。下面的代码演示的是精细flash访问的函数。 例:使用精细Flash访问API函数 #include
#include \#define BUF_SIZE 100 int main (void) {
flash_region* regions; alt_flash_fd* fd;
int number_of_regions; int ret_code;
char write_data[BUF_SIZE];
/* Set write_data to all 0xa */ memset(write_data, 0xA, BUF_SIZE);
fd = alt_flash_open_dev(EXT_FLASH_NAME); if (fd) {
ret_code = alt_get_flash_info(fd, ®ions,
&number_of_regions);
if (number_of_regions && (regions->offset == 0)) {
/* Erase the first block */
ret_code = alt_erase_flash_block(fd, regions->offset,
regions->block_size); if (ret_code) { /*
* Write BUF_SIZE bytes from write_data 100 bytes into * the first block of the flash ret_code = alt_write_flash_block ( fd,
regions->offset,
regions->offset+0x100,
write_data, BUF_SIZE ); } } }
return 0; }
6.5.10 使用 DMA 设备
HAL提供直接存储器访问的设备抽象模型。 这些外设执行从数据源到目的地的大批量的 数据传输。源和目的地可以是存储器或其它的设备,如以太网连接。在HAL DMA设备模型 中,DMA传输属于一下两种分类之一:发送或接收。因此,HAL提供两个设备驱动来实现发送通道和接收通道。发送通道从数据源的缓冲器获得数据,发送数据 到目的设备。接收通道接收数据,并将数据忖道目的缓冲器中。取决于底层的硬件实现,软件可能只能访问两中 端点中的一个。图6-24显示了三种基本的DMA传输。存储器之间的数据拷贝同时包括接收 和发送DMA通道。