【FFH】BearPi_Micro业务和驱动代码_GPIO口使用 原创 精华

X丶昕雪
发布于 2022-5-29 19:25
浏览
1收藏

业务代码and驱动代码框架

【FFH】BearPi_Micro业务和驱动代码_GPIO口使用-鸿蒙开发者社区

业务代码

  1. .c文件编写业务代码
    【FFH】BearPi_Micro业务和驱动代码_GPIO口使用-鸿蒙开发者社区

  2. BUILD.gn把第一步中的业务代码打包成可执行文件,再把可执行文件打包成小组件
    【FFH】BearPi_Micro业务和驱动代码_GPIO口使用-鸿蒙开发者社区

  3. applications.json将小组件打包成名为my_sample组件
    【FFH】BearPi_Micro业务和驱动代码_GPIO口使用-鸿蒙开发者社区

  4. /vendor/…/config.json编译构建组件
    【FFH】BearPi_Micro业务和驱动代码_GPIO口使用-鸿蒙开发者社区

驱动的使用

业务代码

1.获取驱动
HdfIoServiceBind(驱动名称) #驱动对外发布服务的名称,在device_info.hcs里查询
2. 申请内存
HdfSBufObtainDefaultSize()申请发送数据data和接受数据reply的内存
3.将业务代码的数据翻译成驱动代码的数据(翻译数据)
HdfSbufWriteUint8(1,2)将参数二写入参数一,参数一将被步骤四带到驱动代码中
4. 发送和接受驱动的数据
serv->dispatcher->Dispatch(&serv->object,操作确认符, data, reply) 数据通过Dispatch发送接收数据
*serv是第一步HdfIoServiceBind()的返回值
5. 翻译驱动代码发来的数据(翻译数据)
HdfSbufReadInt32(1, &2)将参数一(驱动在步骤四发送来的数据)写入参数二,参数二为业务代码可以查看的数据(参数二为地址)
6. 释放申请的内存
HdfSBufRecycle()将第二步申请的data和reply内存释放
代码如下:

#define LED_WRITE_READ 1
#define LED_SERVICE "hdf_led"

static int SendEvent(struct HdfIoService *serv, uint8_t eventData)
{
    int ret = 0;
    //用HdfSBufObtainDefaultSize申请内存,这种类型的内存才能用于和驱动程序交换数据
    struct HdfSBuf *data = HdfSBufObtainDefaultSize();  
    if (data == NULL)   
    {       //报错情况
        printf("fail to obtain sbuf data!\r\n");
        return 1;
    }
    struct HdfSBuf *reply = HdfSBufObtainDefaultSize();
    if (reply == NULL)  
    {       //报错情况
        printf("fail to obtain sbuf reply!\r\n");
        ret = HDF_DEV_ERR_NO_MEMORY;
        goto out;
    }


    /* 写入数据,将参数二的数据写入参数一中*/
    //将eventData内的数据写入到data里面 
    if (!HdfSbufWriteUint8(data, eventData))
    {       //报错情况
        printf("fail to write sbuf!\r\n");
        ret = HDF_FAILURE;
        goto out;
    }
    /* 参数二为1,判断读写操作码;参数三data通过Dispatch发送到驱动;同时驱动会把数据写入到参数四reply */
    ret = serv->dispatcher->Dispatch(&serv->object, LED_WRITE_READ, data, reply);
    if (ret != HDF_SUCCESS)
    {       //报错情况
        printf("fail to send service call!\r\n");
        goto out;
    }

    int replyData = 0;
    /* 读取驱动的回复数据 */
    if (!HdfSbufReadInt32(reply, &replyData))
    {
        printf("fail to get service call reply!\r\n");
        ret = HDF_ERR_INVALID_OBJECT;
        goto out;
    }
    printf("\r\nGet reply is: %d\r\n", replyData);
out:        //回收先前为和驱动交换数据而申请的内存
    HdfSBufRecycle(data);
    HdfSBufRecycle(reply);
    return ret;
}

int main(int argc, char **argv)
{
    int i;

    /* 获取服务 */
    //获取驱动的服务,获取到服务后通过服务中的Dispatch方法向驱动发送消息。
    //在HDF框架定义的device_info.hcs配置文件中有对应的设备描述,每一个设备驱动都有对外发布服务的唯一名称
    struct HdfIoService *serv = HdfIoServiceBind(LED_SERVICE);
    if (serv == NULL) //当获取服务不成功时
    {
        printf("fail to get service %s!\r\n", LED_SERVICE);
        return HDF_FAILURE; //返回-1
    }

    for (i = 0; i < argc; i++) //打印输入的数据
    {
        printf("\r\nArgument %d is %s.\r\n", i, argv[i]);
    }
    //给驱动发送数据
    SendEvent(serv, atoi(argv[1]));

    HdfIoServiceRecycle(serv); // 回收IoService对象(退订服务)
    printf("exit");

    return HDF_SUCCESS; //返回0
}

驱动代码

新建代码:device\st\drivers\新建代码文件夹\驱动代码+BUILD.gn

  1. 将驱动入口注册到HDF框架中
    HDF_INIT(驱动入口的对象)
    驱动入口的对象必须为HdfDriverEntry类型的全局变量
struct HdfDriverEntry g_ledDriverEntry = {
 .moduleVersion = 1,              //版本号
 .moduleName = "HDF_LED",         //驱动名称
 .Bind = HdfLedDriverBind,        //驱动对外提供的服务能力,将相关的服务接口绑定到HDF框架
 .Init = HdfLedDriverInit,        // 驱动自身业务初始的接口
 .Release = HdfLedDriverRelease,  // 驱动资源释放的接口
 };
  1. 在Dispatch中处理用户态发下来的消息
    LedDriverDispatch(struct HdfDeviceIoClient *client, int cmdCode, struct HdfSBuf *data, struct HdfSBuf *reply)对应参数为业务代码中的第四步

    1. 翻译业务代码带来的数据(翻译数据)
      HdfSbufReadUint8(data,&2);将data数据转换成驱动代码可以使用的数据,完成相应动作(参数二为地址)
    2. 将驱动代码的数据发送到业务代码(翻译数据)
      HdfSbufWriteInt32(reply,2)将参数2写入参数1的reply中,reply可被带至业务程序
      PS:==当需要翻译的数据为字符串时,用函数HdfSbufWriteString(1, 2);2=HdfSbufReadString(1)==
  2. 驱动的BUILD.gn把驱动代码编译成可执行文件

  3. 系统驱动的BUILD.gn中的依赖库添加入==驱动代码的所在文件夹==
    /device/st/drivers/BUILD.gn

  4. 驱动配置(LED灯为例子)

    1. 驱动设备描述
      device\st\bearpi_hm_micro\liteos_a\hdf_config\device_info\device_info.hcs
    device_led :: device {                  // 设备节点
     device0 :: deviceNode {             // 驱动的DeviceNode节点
         policy = 2;                     // policy字段是驱动服务发布的策略
         priority = 10;                 // 驱动启动优先级(0-200),值越大优先级越低,建议默认配100,优先级相同则不保证device的加载顺序
         preload = 1;                    // 驱动按需加载字段
         permission = 0777;              // 驱动创建设备节点权限
         moduleName = "HDF_LED";        // 驱动名称,该字段的值必须和驱动入口结构的moduleName值一致
         serviceName = "hdf_led";    // 驱动对外发布服务的名称,必须唯一,驱动代码将以此名字启用驱动
         deviceMatchAttr = "st_stm32mp157_led"; // 驱动私有数据名称
         }
     }  
    
    1. 驱动的私有配置信息
      驱动的私有(只有该驱动使用)配置可以添加一个配置文件,HDF框架在加载驱动的时候,会将对应的配置信息获取并保存在HdfDeviceObject 中的property里面,通过Bind和Init传递给驱动,在device\st\bearpi_hm_micro\liteos_a\hdf_config\led\led_config.hcs中添加有配置描述。
    root {
     LedDriverConfig {
         led_gpio_num = 13;
         match_attr = "st_stm32mp157_led";   
     //该字段的值必须和device_info.hcs中的deviceMatchAttr值一致,以便于该私有配置可以被调用
         }
     }
    

    配置信息定义之后,需要将该配置文件添加到板级配置入口文件device\st\bearpi_hm_micro\liteos_a\hdf_config\hdf.hcs,示例如下:

    #include "led/led_config.hcs"
    

GPIO口使用

GPIO口写入操作

==GPIO口一组16个,按顺序排列。==
例如当使用到GPIOA0时,IO口设置为16*0+0=0;当使用GPIOB1时,IO口设置为16*1+1=17
在驱动代码中添加以下代码:

//位置:bearpi-hm_micro_small\drivers\framework\support\platform\src\gpio_if.c
#include "gpio_if.h"

/*1*/   
//IO口设置函数
GpioSetDir(uint16_t gpio, uint16_t dir);	//dir的值查询GPIO口模式设置
/*2*/    
//GPIO口操作函数
GpioWrite(uint16_t gpio, uint16_t val);
GpioRead(uint16_t gpio, uint16_t *val);

IO口设置和操作函数的调用

//IO口设置调用的函数
GpioCntlrSetDir(GpioGetCntlr(gpio), GpioToLocal(gpio), dir);    //调用函数
GpioCntlrSetDir(struct GpioCntlr *cntlr, uint16_t gpio, uint16_t dir);    //函数头
cntlr->ops->setDir(cntlr, local, dir);      //操作
//IO写入值
GpioCntlrWrite(GpioGetCntlr(gpio), GpioToLocal(gpio), val);      //调用函数
GpioCntlrWrite(struct GpioCntlr *cntlr, uint16_t local, uint16_t val); //函数头
cntlr->ops->write(cntlr, local, val);       //操作

GPIO口模式设置

GpioSetDir(uint16_t gpio, uint16_t dir);
typedef enum {
        E53_GPIO_Out_PullUp = 0,
        E53_GPIO_Out_PullDown,
        E53_GPIO_Out_PullNone,
        E53_GPIO_Out_DrainUp,
        E53_GPIO_Out_DrainDown,
        E53_GPIO_In_Floating,
        E53_GPIO_In_Up,
        E53_GPIO_In_Down,
    }E53_GPIO_Mode;

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
已于2022-7-30 15:00:59修改
3
收藏 1
回复
举报
回复
    相关推荐