2022/10/24——SPI设备驱动练习

编写驱动文件和test.c,实现使用test.c访问驱动并控制数码管显示的数据

设备树节点的编写

&spi4{
  
     pinctrl-names = "default", "sleep";
pinctrl-0 = <&spi4_pins_b>;
pinctrl-1 = <&spi4_sleep_pins_b>;
                
         cs-gpios = <&gpioe 11 0>;//代表片选线
         status = "okay";   

      m74hc595@0 {//0表示是SPI总线上的第0个设备
        compatible = "hqyj,m74hc595";
        reg = <0>;
        spi-max-frequency = <10000000>;//SPI总线速率
 
        //59MHZ        
      };
    };

驱动文件

#include <linux/init.h>
#include <linux/module.h>
#include <linux/spi/spi.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/cdev.h>
#include <linux/ioctl.h>
#include <linux/device.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>

#define CNAME  "myspi"

unsigned int major;

struct class *cls;//句柄
struct device *dev;
struct spi_device *myspi=NULL;
long ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    char buf[2]={};
    buf[0]=cmd;
    if(cmd == 0x5)
        buf[0]=0x2;
    buf[1]=arg;
    spi_write(myspi,buf,sizeof(buf));
    return 0;
}
//操作方法结构体的初始化
struct file_operations fops=
{
    .unlocked_ioctl=ioctl,
};
int m74hc595_probe(struct spi_device *spi)
{
    myspi=spi;
    //动态注册字符设备驱动
    major=register_chrdev(0,CNAME,&fops);
    if(major<0)
    {
        printk("字符设备驱动注册失败\n");
        return major;
    }
    printk("字符设备驱动注册成功major=%d\n",major);
    //向上提交节点目录
    cls=class_create(THIS_MODULE,"LED");
    if(IS_ERR(cls))
    {
        printk("向上提交目录失败\n");
        return PTR_ERR(cls);
    }
    printk("向上提交目录成功\n");
    //创建设备节点文件
    dev=device_create(cls,NULL,MKDEV(major,0),NULL,"myspi");
    if(IS_ERR(dev))
    {
        printk("创建节点失败\n");
        return PTR_ERR(dev);
    }
    printk("创建节点成功\n");
    //初始化队列头
    //init_waitqueue_head(&wq_head);
    printk("%s:%d\n",__FILE__,__LINE__);
    return 0;
}
int m74hc595_remove(struct spi_device *spi)
{
    //销毁节点
    device_destroy(cls,MKDEV(major,0));
    //销毁目录
    class_destroy(cls);
    //注销字符设备驱动
    unregister_chrdev(major,CNAME);
    printk("%s:%d\n",__FILE__,__LINE__);
    return 0;
}
//设备树匹配表
struct of_device_id of_table[]={
    {.compatible="hqyj,m74hc595"},
    {},
};
MODULE_DEVICE_TABLE(of,of_table);
//定义SPI对象并初始化
struct spi_driver m74hc595={
    .probe=m74hc595_probe,
    .remove=m74hc595_remove,
    .driver={
        .name="m74hc595",
        .of_match_table=of_table,
    },
};

module_spi_driver(m74hc595);
MODULE_LICENSE("GPL");

test.c——测试文件

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <unistd.h>
/*管脚顺序由h到a
 *0011 1111     0x3F   0
 *0000 0110     0x06   1
 *0101 1011     0x5B   2
 *0100 1111     0x4F   3
 *0110 0110     0x66   4
 *0110 1101     0x6D   5 
 *0111 1101     0x7D   6
 *0000 0111     0x07   7
 *0111 1111     0x7F   8
 *0110 1111     0x6F   9
 * */

int main(int argc,char const *argv[])
{
    long led[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
    int which[]={0x1,0x5,0x4,0x8};
    int fd,number,val;
    fd=open("/dev/myspi",O_RDWR);
    if(fd<0)
    {
        printf("打开文件失败\n");
        exit(-1);
    }
    printf("打开文件成功\n");
    while(1)
    {
        printf("请输入想要改变的数码管(1~4) 5:关闭所有的数码管并退出程序\n");
        scanf("%d",&val);
        if(val==5)
        {
            for(int i=0; i<4; i++)
            {
                ioctl(fd,which[i],0);
            }
            printf("程序即将退出\n");
            break;
        }else if(val<=4 && val>=1 )
        {
            printf("请输入第%d个数码管的数字(0~9)\n",val);
            scanf("%d",&number);
            ioctl(fd,which[val-1],led[number]);
        }else
        {
            printf("输入有误,请重新输入\n");
        }

    }
    close(fd);
    return 0;
}

实验现象

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

命如星火

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值