裸机驱动模板

来源:互联网 发布:淘宝申请介入会退款吗 编辑:程序博客网 时间:2024/06/15 00:28

编写裸机驱动,一般都比较随意。这通常导致代码不统一,移植性差。

本例以SPI FLASH来分析一种优秀的裸机驱动编写模板。

 

首先定义一个设备类。

 

/*

 *flash device class

 */

typedef struct flash_dev_s{

 const struct flash_dev_funs *funs;          /* Function pointers */

 uint32                     flags;          /* Devicecharacteristics */

 hsaddr_t                   start;          /* First address*/

 hsaddr_t                   end;            /* Last address */

 uint32                     num_block_infos;/* Number of entries */

 const flash_block_info_t   *block_info;    /* Info about oneblock size */

 

 const void                 *priv;          /* Devices privatedata */

} flash_dev_t;

 

/* Structure of pointers to functions inthe device driver */

Struct  flash_dev_funs {

 sys_error_t (*flash_init) (struct flash_dev_s *dev) REENTRANT;

 sys_error_t (*flash_erase_block) (struct flash_dev_s *dev,

                                    hsaddr_tblock_base) REENTRANT;

 sys_error_t (*flash_program) (struct flash_dev_s *dev,

                                hsaddr_t base,

                                const void*ram_base, size_t len) REENTRANT;

 sys_error_t (*flash_read) (struct flash_dev_s *dev,

                             const hsaddr_tbase,

                             void* ram_base,size_t len) REENTRANT;

};

同一种设备类型可能有不同厂家和不同参数的差异,但它的大体功能属性是一致的。我们首先把一致的属性剥离出来,构建一个设备类。类似C++的类,包含数据和操作方法。一个设备驱动模板的雏形就出来了。

 

我们来看一个设备实例来看它的方便之处。

struct flash_dev_funs mx25l_funs = {

   mspi_init,

   m25lxx_erase_block,

   m25lxx_program,

   m25lxx_read,

   NULL

};

 

flash_dev_t n25q256_dev = {

   &mx25l_funs,

   FLAG_FSR_POLL,

   CFG_FLASH_START_ADDRESS,

   0,

   1,

   &n25q256_info,

   NULL };

flash_dev_t w25q16_dev = {

   &mx25l_funs,

   0,

  CFG_FLASH_START_ADDRESS,

   0,

   1,

  &w25q16cv_info,

  NULL };

/*end*/

 

flash_dev_t w25q64cv_dev = {

   &mx25l_funs,

   0,

   CFG_FLASH_START_ADDRESS,

   0,

   1,

   &w25q64cv_info,

NULL };

 

这里用一个通用设备结构体定义和初始化了多个不同的spi设备实例。我们看到每个设备的不同之处在它们的功能函数和设备属性。当我们需要新增一个设备时,只需定义一个通用设备类,再去添加它自己的操作方法和数据属性就行了。实现这些之后,对外部调用来说就简单了,直接操作这个设备类的统一接口,上层代码不需要做任何改动,提高了驱动移植性。


我们还可以做进一步的函数封装。

例如:把设备操作完全屏蔽,上层代码不需要管是什么设备。

sys_error_t
flash_read(hsaddr_t flash_base, void *ram_base, size_t len)
{

    dev = board_get_flash_dev();
    if (!dev) {
        return SYS_ERR;
    }

    rv = (*dev->funs->flash_read)(dev, addr, ram, this_read);

    ......

}

0 0