|  | 
 
| Learn lumit Step 8 :  代码可复用性 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
 至此,前面大致介绍了 lumit4510 开发板上 bootloader 启动的基本知识点。
 后面,我们将以板上的每一个硬件设备驱动程序为例,分析一下每个硬件驱动是如何
 让硬件工作起来的。
 
 在重写这些设备接口的过程中,我们希望能够在最大程度上将与硬件无关的代码
 提供给大家,以便移植和重用;而把和硬件相关的最底层的那些实现独立出来,单独
 实现为一个类似linux设备驱动的driver。这样,大家需要做的仅仅是根据你自己的
 硬件设计修改最底层的接口函数,而绝大部分的上层代码都可以无需修改移植到新的
 板子上。
 
 首先,我们以 LED 灯的驱动为例,来说明这个想法。本来这个驱动是非常简单的,
 甚至只用几个宏定义就能实现 LED 灯的点亮和熄灭,但在这里我们反过来,把简单的
 东西复杂化,为的是建立一种结构和层次来应付更多复杂的问题。
 
 这个项目下有 4 个和 led 相关的文件,分别是 led_driver.c[.h] led_api.c[.h]
 顾名思义即可知道 led_driver 是底层的硬件相关实现代码,led_api 是提供给上层的
 统一接口,与底层硬件无关。
 
 我们从底层开始介绍 led_driver 的实现,主要是有如下五个函数:
 
 int led_open( void );
 
 int led_read( char * buf, int count );
 
 int led_write( char * buf, int count );
 
 int led_ioctl( unsigned int cmd, unsigned long arg );
 
 int led_release( void );
 
 其中 open, read, write, ioctl, release 是模仿了 linux 设备驱动的写法,尽量
 采用了统一的接口,将设备操作虚拟为文件读写来进行。以 led_read 为例:
 
 int led_read( char * buf, int count )
 {
 int i = 0;
 
 // the count has exceeds the count of our board
 if( count > 4 )
 return -1;
 
 for( i = 0; i < count; i++ )
 buf = led_status;
 
 return 0;
 }
 
 我们分析一下 led 设备的读操作,输入参数是读缓冲 buf 指针和要读的字节数 count 。
 如果每次读字节数超过 4 个(led),则我们认为错误,返回 -1 ;否则我们将前面 count 个
 led 的状态信息,分别写入 buf 指针中,0 表示 OFF,1 表示 ON ,并直接返回 count
 表示已经成功读出 count 字节的设备数据。
 
 同样 led 写操作也类似,即将从上层传入的 buf 信息,写入 led 对应的 led_status
 内部状态标识数组中,同时修改 IO 寄存器相应位来实现对硬件的驱动,真正点亮或者熄灭
 led 小灯。
 
 这里我们还定义了 LED_NUM 表示目前只支持 4 个 led 。
 
 但是对于上层用户来说,这样的驱动接口很不直观,也很难直接用于应用编程中。因此,
 我们实现了 led_api 来对 led_driver 进行一次封装,使得 led_api 提供的接口更为直观,
 具有更好的代码可读性和可移植性,这两点对于嵌入式程序来说是非常重要的。
 
 led_api 主要实现了如下一系列接口:
 int led_init( void );
 
 /* get 4 leds status to low-4-bits of hex value */
 int led_get_value( void );
 
 /* set hex value of low-4-bits to 4 leds */
 int led_set_value( int value );
 
 int led_all_light( void );
 
 int led_all_dark( void );
 
 int led_all_blink( void );
 
 int led_one_light( int position );
 
 int led_one_dark( int position );
 
 int led_one_blink( int position );
 
 int led_test( void );
 
 其中,led_init 是硬件初始化函数,实际调用的即驱动的 open 操作;led_set_value
 和 led_get_value 是以 32 位整型数的每一个 bit 表示一个 led 灯,进行设置和读取的接口;
 其他的 led_ 函数,主要就是点亮和熄灭以及闪烁的接口,分为全部和单个两组;在最后是一个
 led_test 函数,是为了便于用户调用和理解写的一个接口测试例子,如果对 led_api 不熟悉,
 就可以先用 led_test 做一下测试,看看应该如何传递参数和获得返回结果。
 
 对于上层调用来说,使用的是抽象出来的个数为 LED_NUM 的 led 灯。它可以在实际使用中
 灵活调整,底层的硬件驱动则保证了当传入的 count 超过 4 的时候,硬件驱动接口返回失败,
 表示无法执行对该设备的读/写操作,原因是底层硬件不支持。
 
 因此,当在一个新的开发板上实现 led 接口的时候,只需要对 led_driver 做改动,而无需
 修改 led_api 已有的接口,可以直接重用;这样分层结构的好处是,便于为上层的复杂应用提供
 更多的接口,更快地实现上层需求,同时底层共用一个统一的驱动接口,大家就可以为 led_api
 增添更多的 api 来实现不同的闪烁效果,例如跑马灯等。
 
 当每个人都为 led_api 贡献一个 api 的时候,就避免了其他人在自己系统之上再去实现这个
 api 的工作,减少了大量的重复劳动,而可以把工作专注于上层的应用开发和底层的驱动接口实现。
 我想,这也是 lumit 开源项目的目标之一。
 | 
 
×本帖子中包含更多资源您需要 登录 才可以下载或查看,没有账号?注册  |