如何写便于移植的驱动,以软件模拟 QSPI 为例

SAL_QSPI ( Sofetware Abstraction Layer - QSPI )

  • 这是一个极为通用的软件抽象 4 线 spi 模拟驱动,移植到不同平台只需要实现两个函数

  • 仓库链接:https://gitee.com/wattercutter/sal_qspi

在这里插入图片描述

用法

在工程中加入 ./include/_sal_qspi_mod.h./src/_sal_qspi_mod.c, 调用方法见 ./demo/test_main.c

#include "_sal_qspi_mod.h"

void delay_us(unsigned int us_){
    // porting
};
void set_pin(unsigned int pin_, unsigned int val_){
    // porting
};

int main()
{
    sal_qspi_info_t devx = {    
        .cs_num_ = 1,
        .clk_pin_ = 2,
        .cs_pins_ = {3,4,5,6,7,8,9,10,},
        .dat_pins_ = {11,12,13,14}
    };

    // registering delay & set_pin function, reset 1 cs pin, reset dat pins
    sal_qspi_init(
        (sal_qspi_info_t*)&devx,
        (unsigned long long)1,
        // _STAUS_HIGH_LEVEL,
        // _STAUS_HIGH_LEVEL, 
        delay_us,
        set_pin
    );

    while(1){
        // write [64]-bits data [0x12345678abcdef] to selected chip [(unsigned long long)0], info contained in [devx]
        sal_qspi_wdat_64bit(
            (sal_qspi_info_t*)&devx,
            (unsigned long long)0,
            (unsigned long long)0x12345678abcdef,
            (unsigned long long)64
        );
    }
}

逐块说明一下:

1

#include "_sal_qspi_mod.h"

这是驱动的头文件,调用驱动的程序需要 #include 这个文件

2

void delay_us(unsigned int us_){
    // porting
};
void set_pin(unsigned int pin_, unsigned int val_){
    // porting
};

这是要在初始化时传入的两个函数,

  • delay_us:以 1us 为基数进行延时,传参 us_ 表示延时 us_ 个微妙
  • set_pin:把指定引脚 pin_ 的输出设置为 val_
    这两个函数用于适配不同的硬件平台,比如使用不同的处理器就需要用对应的库/驱动实现这两个接口,供给 sal_qspi 的驱动去调用,这样就不需要修改驱动本身了。

这实际上是 sal_qspi 通过函数指针实现了方法的注册,减少了使用者阅读驱动源码的负担。

3

sal_qspi_info_t devx = {    
	.cs_num_ = 1,
	.clk_pin_ = 2,
	.cs_pins_ = {3,4,5,6,7,8,9,10,},
	.dat_pins_ = {11,12,13,14}
};

这是准备 sal_sqpi 的基本信息,用到的结构体的原型如下:

typedef struct sal_qspi_info_{
    unsigned int cs_num_;
    unsigned int cs_pins_[SAL_QSPI_CS_MAX_NUM];
    unsigned int clk_pin_;
    unsigned int dat_pins_[4];
}sal_qspi_info_t;
  • cs_num_ 指的是片选信号的数量
  • cs_pins_[SAL_QSPI_CS_MAX_NUM] 指的是各个片选信号对应的 gpio 引脚号
  • clk_pin_ 指的是时钟信号对应的 gpio 引脚号
  • dat_pins[4] 指的是 4 个数据信号线对应的 gpio 引脚号
    这样我们就知道上面的代码描述的 qspi 基本信息就是:有 1 个 片选,对应的引脚号是 3,时钟信号对应的引脚号是 2,4 个数据线对应的引脚号分别是 11、12、13、14

4

// registering delay & set_pin function, reset 1 cs pin, reset dat pins
    sal_qspi_init(
        (sal_qspi_info_t*)&devx,
        (unsigned long long)1,
        delay_us,
        set_pin
    );

这里是把前面实现的延时函数、gpio 操作函数两个接口函数注册到我们要初始化的 sal_qspi 设备信息中。用到的函数原型如下:

void 
sal_qspi_init(
    sal_qspi_info_t* sal_qspi_dev_,
    unsigned long long cs_num,
    void(*delay_us_)(unsigned int us_),
    void(*set_pin_val_)(unsigned int pin_, unsigned int val_)
); // register delay call back function, reset gpio pin output 

注意后两个参数是函数指针,一个是 void(*)(unsigned int) 类型的,另一个是 void(*)(unsigned int, unsigned int) 类型的。

5

发送数据的函数原型如下:

void 
sal_qspi_wdat_64bit(
    sal_qspi_info_t* sal_qspi_dev_,
    unsigned long long csn_,
    unsigned long long dat_,
    unsigned long long bits_num_
);

发送数据的位宽 bits_num_ 范围为 1-64 bits,需要是 4 的整数倍,不同位宽的发送时序如下:

bits_num_==24

在这里插入图片描述

bits_num_==8

在这里插入图片描述

例程

  • 路径:./demo/test_main.c
  • 包含路径:./include/
  • 源文件:./src/*.c

移植说明

参考 …/demo/test_main.c,仅需实现以下两个函数(函数名任意)并作为参数在初始化时传入

void delay_us(unsigned int us_){
    // porting
};
void set_pin(unsigned int pin_, unsigned int val_){
    // porting
};

函数说明如下:

  • delay_us:以 1us 为基数进行延时,传参 us_ 表示延时 us_ 个微妙
  • set_pin:把指定引脚(pin_)的输出设置为 _val

约束

  • 初始化不包含对应引脚的复用配置,请在 sal_qspi 初始化前完成相应配置
  • 13
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值