途牛网站建设的基本特点,网站营销外包公司,中国建筑材料网,那些网站做任务能赚钱SPI总线驱动整体上与I2C总线驱动类型#xff0c;差别主要在设备树和数据传输上#xff0c;由于SPI是由4根线实现主从机的通信#xff0c;在设备树上配置时需要对SPI进行设置。
原理图可知#xff0c;数码管使用的SPI4对应了单片机上的PE11--SPI4-NSS,PE12--SPI4-S…SPI总线驱动整体上与I2C总线驱动类型差别主要在设备树和数据传输上由于SPI是由4根线实现主从机的通信在设备树上配置时需要对SPI进行设置。
原理图可知数码管使用的SPI4对应了单片机上的PE11--SPI4-NSS,PE12--SPI4-SCK,PE13--SPI4-MISO,PE14--SPI4-MOSI 设备树信息
需要注意在SPI4设备树信息中一定要加spi-max-frequency属性该属性用于设置spi的主频如果没有可能出现无法正常启动spi或启动spi后控制数码管时数码管显示出现错位现象 驱动源码
#include linux/init.h // 包含内核初始化相关的头文件
#include linux/module.h // 包含内核模块相关的头文件
#include linux/of.h // 包含设备树操作相关的头文件
#include linux/gpio.h // 包含 GPIO 操作相关的头文件
#include linux/of_gpio.h // 包含设备树 GPIO 相关的头文件
#include linux/fs.h // 包含文件操作相关的头文件
#include linux/uaccess.h // 包含用户空间访问内核空间相关的头文件
#include linux/device.h // 包含设备相关的头文件
#include linux/cdev.h // 包含字符设备相关的头文件
#include linux/slab.h // 包含内存分配相关的头文件
#include linux/spi/spi.h // 包含 SPI 相关的头文件
#include spi_test.h // 包含自定义头文件//创建设备号
static int major;
//创建类
static struct class *cls;
//创建设备
static struct device *device;
//创建SPI设备
static struct spi_device *spi_dev;
//保存字符设备数据
static char spi_buf[128];static int myspi_open(struct inode *inode, struct file *file)
{unsigned int cmajor;//保存次设备号cmajor iminor(inode);//将次设备号保存到file结构体的private_data中file-private_data (void *)cmajor;printk(spi_open\n);return 0;
}static int myspi_close(struct inode *inode, struct file *file)
{printk(spi_close\n);return 0;
}static ssize_t myspi_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{unsigned int ret;//从内核空间读取数据到用户空间如果读取数据的长度大于spi_buf的长度按照最大长度读取if(count sizeof(spi_buf)){count sizeof(spi_buf);}ret copy_to_user(buf, spi_buf, count);if(ret 0){printk(copy_to_user failed\n);return -1;}printk(spi_read\n);return 0;
}static ssize_t myspi_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{unsigned int ret;//将用户空间的数据拷贝到内核空间如果传输数据的长度大于spi_buf的长度按照最大长度传输if (count sizeof(spi_buf)){count sizeof(spi_buf);}ret copy_from_user(spi_buf, buf, count);if (ret 0){printk(copy_from_user failed\n);return -1;}printk(spi_write\n);return 0;
}static int myspi_write_data(const uint8_t cmd, const uint8_t data)
{uint8_t spi_buf1[2] {cmd, data};int ret 0;printk(cmd %x\n, spi_buf1[0]);ret spi_write(spi_dev, spi_buf1, 2);return ret;
}static long myspi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{uint8_t data;unsigned long ret ;//从用户空间读取数据ret copy_from_user(data, (void *)arg, sizeof(data));if (ret 0){printk(copy_from_user failed\n);return -1;}//根据cmd的值进行不同的操作 switch (cmd){case SET_DAT0:ret myspi_write_data(0x01, data);break;case SET_DAT1:ret myspi_write_data(0x02, data);break;case SET_DAT2:ret myspi_write_data(0x04, data);break;case SET_DAT3:ret myspi_write_data(0x08, data);break; case SET_DAT4:ret myspi_write_data(0x0f, data);break;default:break;}if (ret ! 0){printk(spi_write failed\n);return -1;}printk(spi_ioctl, data %x\n, data);return 0;
}//定义file_operations结构体
struct file_operations fops {.owner THIS_MODULE,.open myspi_open,.release myspi_close,.read myspi_read,.write myspi_write,.unlocked_ioctl myspi_ioctl,
};//编写spi设备驱动
int myspi_probe(struct spi_device *spi)
{//unsigned char buf[]{0X01,0X6D};//0X01表示写数据0X6D表示写入的数据//spi_write(spi,buf,sizeof(buf));//给从机发送一个数据让最左边数码管显示数字5printk(myspi_probe\n);spi_dev spi;//1.创建设备号major register_chrdev(0, myspi, fops);if (major 0){printk(register_chrdev failed\n);return -1;}//2.创建类cls class_create(THIS_MODULE, myspi);if (IS_ERR(cls)){printk(class_create failed\n);unregister_chrdev(major, myspi);return -1;}//3.创建设备device device_create(cls, NULL, MKDEV(major, 0), NULL, myspi);if (IS_ERR(device)){printk(device_create failed\n);class_destroy(cls);unregister_chrdev(major, myspi);return -1;}return 0;
}int myspi_remove(struct spi_device *spi)
{printk(myspi_remove\n); device_destroy(cls, MKDEV(major, 0));class_destroy(cls);unregister_chrdev(major, myspi);return 0;
}static const struct of_device_id spi_table[] {{ .compatible johnson,m74hc595, },{ /* sentinel */ },
};struct spi_driver myspi_driver {.probe myspi_probe,.remove myspi_remove,.driver {.name m74hc595,.of_match_table spi_table,},
};//一键注册宏定义
module_spi_driver(myspi_driver);
MODULE_LICENSE(GPL); //声明开源许可头文件
#ifndef __SPITEST_H__
#define __SPITEST_H__#define SET_DAT0 _IOW(s, 0, int)
#define SET_DAT1 _IOW(s, 1, int)
#define SET_DAT2 _IOW(s, 2, int)
#define SET_DAT3 _IOW(s, 3, int)
#define SET_DAT4 _IOW(s, 4, int)#endif
应用程序 -- 实现在数码管上依次显示数字
#include stdio.h
#include fcntl.h
#include unistd.h
#include sys/ioctl.h
#include arpa/inet.h
#include spi_test.hconst uint8_t num[10] {0X3F,0X06,0X5B,0X4F,0X66,0X6D,0X7D,0X07,0X7F,0X6F};int main()
{int fd 0;int date 0;//打开设备文件fd open(/dev/myspi, O_RDWR);if (fd 0){printf(open myspi failed\n);return -1;}while(1){ioctl(fd, SET_DAT0, num[date]);sleep(1);ioctl(fd, SET_DAT1, num[date]);sleep(1);ioctl(fd, SET_DAT2, num[date]);sleep(1);ioctl(fd, SET_DAT3, num[date]);sleep(1);ioctl(fd, SET_DAT4, num[date]);if (date 9){date 0;}sleep(1);} //关闭设备文件close(fd);return 0;
}