STM32MP157 | 基于 Linux SPI 驱动M74HC595数码管显示
一、M74HC595简介
M74HC595器件是采用硅栅C2MOS技术制作的具有输出锁存器(3态)的高速CMOS 8位移寄存器。
该设备包含一个8位串行进、并行出移位寄存器,它提供一个8位d型存储寄存器。存储寄存器有8个3状态输出。为移位寄存器和存储寄存器都提供了单独的时钟。
移位寄存器有直接覆盖清除,串行输入和串行输出(标准)引脚级联。移位寄存器和存储寄存器都使用正边缘触发时钟。如果两个时钟连接在一起,移位寄存器状态将始终是存储寄存器前面的一个时钟脉冲。
特性:
- 高速:在Vcc = 6V时,fMAx = 59mhz(典型)
- 低功耗:Icc = 4 μA (max)
- 工作电压范围宽:Vcc (opr.) = 2 V至6 V
1.M74HC595设备操作原理图:
2. 开发板原理图
二、 添加设备树的节点
1.设置引脚
首先设置spi引脚的复用功能,找到 spi4_pins_b 节点:
vi stm32mp15-pinctrl.dtsi
2. 找出控制器的设备树
stm32mp151.dtsi
spi4: spi@44005000 {#address-cells = <1>; #size-cells = <0>; compatible = "st,stm32h7-spi"; reg = <0x44005000 0x400>;interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>;clocks = <&rcc SPI4_K>;resets = <&rcc SPI4_R>;dmas = <&dmamux1 83 0x400 0x01>,<&dmamux1 84 0x400 0x01>;dma-names = "rx", "tx";power-domains = <&pd_core>;status = "disabled";
};
3. 根据内核帮助文档编写自己的设备树
/home/linux/linux-5.10.61/Documentation/devicetree/bindings/i2c/
&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{compatible = "m74hc595";reg = <0>;spi-max-frequency = <10000000>; //10Mhz};
};
4. 重新编译设备树
make dtbs
重启开发板
安装驱动
三. 编写M74HC595设备驱动
1.先搭个spi设备驱动框架
#include <linux/init.h>
#include <linux/module.h>
#include <linux/spi/spi.h>int m74hc595_probe(struct spi_device *spi)
{printk("%s:%d\n", __func__, __LINE__);return 0;
}
int m74hc595_remove(struct spi_device *spi)
{printk("%s:%d\n", __func__, __LINE__);return 0;
}struct of_device_id oftable[] = {{.compatible = "m74hc595"}{},
};MODULE_DEVICE_TABLE(of, oftable);struct spi_driver m74hc595 = {.probe = m74hc595_probe,.remove = m74hc595_remove,.driver = {.name = "hello",.of_match_table = oftable,},
};module_spi_driver(m74hc595);
MODULE_LICENSE("GPL");
2. 写个Makefile编译一下:
ifeq ($(arch),arm)
KERNELDIR :=/home/linux/linux-5.10.61
CROSS_COMPILE ?=arm-linux-gnueabihf-
else
KERNELDIR :=/lib/modules/$(shell uname -r)/build
CROSS_COMPILE ?=
endif modname ?=
PWD :=$(shell pwd)CC :=$(CROSS_COMPILE)gccall:make -C $(KERNELDIR) M=$(PWD) modules# $(CC) test.c -o test
clean:make -C $(KERNELDIR) M=$(PWD) clean# rm testinstall:cp *.ko ~/nfs/rootfs/# cp test ~/nfs/rootfs/help:echo "make arch = arm or x86 modname= dirvers file name"obj-m:=$(modname).o
linux@ubuntu:~/linu/driver/csdn/M74HC595$ make arch=arm modname=m74hc595
3. 再写字符设备驱动框架
#include <linux/init.h>
#include <linux/module.h>
#include <linux/spi/spi.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>#define CNAME "m74hc595"int major = 0;
int minor = 0;
int count = 1;
dev_t devno;
struct cdev *cdev;
struct class *cls;
struct device *dev;int m74hc595_open(struct inode *inode, struct file *file)
{printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);return 0;
}
long m74hc595_ioctl(struct file *file, unsigned int cmd, unsigned long args)
{printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);return 0;
}int m74hc595_close(struct inode *inode, struct file *file)
{printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);return 0;
}
const struct file_operations fops = {.open = m74hc595_open,.unlocked_ioctl = m74hc595_ioctl,.release = m74hc595_close,
};int m74hc595_probe(struct spi_device *spi)
{int ret;// 1.分配对象cdev = cdev_alloc();if (cdev == NULL){printk("alloc memory failed\n");ret = -ENOMEM;goto ERR1;}// 2.初始化对象cdev_init(cdev, &fops);// 3.申请设备号if (major > 0){ret = register_chrdev_region(MKDEV(major, minor), count, CNAME);if (ret != 0){printk("static:alloc device number failed!\n");goto ERR2;}}else if (major == 0){ret = alloc_chrdev_region(&devno, 0, 1, CNAME);if (ret != 0){printk("dynamic:alloc device number failed!\n");goto ERR2;}major = MAJOR(devno);minor = MINOR(devno);}// 4.注册对象ret = cdev_add(cdev, MKDEV(major, minor), count);if (ret){printk("add cdev failed\n");goto ERR3;}// 5.向上层提交目录的信息cls = class_create(THIS_MODULE, "hello");if (IS_ERR(cls)){printk("create class failed\n");ret = PTR_ERR(cls);goto ERR4;}// 6.向上层提交设备的信息dev = device_create(cls, NULL, MKDEV(major, minor), NULL, CNAME);if (IS_ERR(dev)){printk("create device failed\n");ret = PTR_ERR(dev);goto ERR5;}return 0;
ERR5:class_destroy(cls);
ERR4:cdev_del(cdev);
ERR3:unregister_chrdev_region(MKDEV(major, minor), count);
ERR2:kfree(cdev);
ERR1:return ret;
}
int m74hc595_remove(struct spi_device *spi)
{device_destroy(cls,MKDEV(major,minor));class_destroy(cls);cdev_del(cdev);unregister_chrdev_region(MKDEV(major, minor), count);kfree(cdev);return 0;
}struct of_device_id oftable[] = {{.compatible = "m74hc595"},{},
};MODULE_DEVICE_TABLE(of, oftable);struct spi_driver m74hc595 = {.probe = m74hc595_probe,.remove = m74hc595_remove,.driver = {.name = "m74hc595",.of_match_table = oftable,},
};module_spi_driver(m74hc595);
MODULE_LICENSE("GPL");
4.封装spi操作结构体
全局变量中添加成员:
struct spi_device *gspi;
u8 code[] = {0x3f, //00x06, //10x5b, //20x4f, //30x66, //40x6d, //50x7d, //60x07, //70x7f, //80x6f, //90x77, //A0x7c, //b0x39, //c0x5e, //d0x79, //e0x71, //f
};u8 which[] = {0x1, //sg00x2, //sg10x4, //sg20x8, //sg3
};
6.M74HC595写数据
(1)新建头文件,封装头文件命令码
#ifndef __M74HC595_H__
#define __M74HC595_H__
#define SEG_WHICH _IOW('K',0,int)
#define SEG_DAT _IOW('K',1,int)
#endif
(2)添加头文件
#include <linux/uaccess.h> //ioctl
#include "m74hc595.h"
(3)在m74hc595_probe中添加
gspi = spi;
(4)直接调用内核封装好的接口
spi_write(gspi,&which[args],1)
7.字符设备驱动的实现
open
int m74hc595_open(struct inode *inode, struct file *file)
{printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);return 0;
}
ioctl
long m74hc595_ioctl(struct file *file, unsigned int cmd, unsigned long args)
{switch(cmd){case SEG_WHICH:spi_write(gspi,&which[args],1);break;case SEG_DAT:spi_write(gspi,&code[args],1);break;default: printk("ioctl error\n");break;}return 0;
}
close
int m74hc595_close(struct inode *inode, struct file *file)
{printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);return 0;
}
四、测试驱动模块
1.加载驱动,查看驱动
insmod
lsmod
2.编写app测试程序
循环打印0-f这16位数
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include "m74hc595.h"int main(int argc, char const *argv[])
{int which = 0;int data = 0;int fd;fd = open("/dev/m74hc595",O_RDWR);if(fd < 0){perror("open error");return -1;}while (1){ioctl(fd,SEG_WHICH,which);which ++;ioctl(fd,SEG_DAT,data);data ++;if(which > 4)which = 0;if(data > 16)data = 0;sleep(1);}close (fd);return 0;
}
显示成功
STM32MP157 | 基于 Linux SPI 驱动M74HC595数码管显示相关推荐
- i.MX6ULL驱动开发 | 14 - 基于 Linux SPI 驱动框架读取ICM-20608传感器
本系列文章驱动源码仓库,欢迎Star~ https://github.com/Mculover666/linux_driver_study. 一.ICM20608 1. 简介 InvenSense 的 ...
- Linux SPI驱动框架(2)——控制器驱动层
SPI控制器驱动层 上节中,讲了SPI核心层的东西,这一部分,以全志平台SPI控制器驱动为例,对SPI控制器驱动进行说明. SPI控制器驱动,即SPI硬件控制器对应的驱动,核心部分需要实现硬件SP ...
- Linux SPI驱动学习——调用SPI读写函数
Linux SPI驱动学习--调用SPI读写函数 博客说明 开发环境 1. 基于W25Q16型FLASH来看SPI的读写函数 附录 博客说明 撰写日期 2019.10.25 完稿日期 未完稿 最近维护 ...
- Linux SPI驱动框架(3)——设备驱动层
SPI设备驱动层 Linux SPI驱动框架(1)和(2)中分别介绍了SPI框架中核心层,和控制器驱动层.其实实际开发过程中,不是IC原厂工程师比较少会接触控制器驱动层,设备驱动层才是接触比较多的 ...
- i.MX6ULL驱动开发 | 13 - Linux SPI 驱动框架
Linux SPI 驱动框架分为两部分: SPI总线控制器驱动:SOC的 SPI 控制器外设驱动 SPI设备驱动:基于SPI总线控制器驱动编写,针对具体的SPI从机设备 一.SPI总线控制器驱动 基于 ...
- linux spi不使用框架,Linux spi驱动框架之执行流程
Linux spi驱动架构由三部分构成:SPI核心层.SPI控制器驱动层.和SPI设备驱动程序. 1.SPI核心层: SPI核心层是Linux的SPI核心部分,提供了核心数据结构的定义.SPI控制器驱 ...
- linux i2c adapter 增加设备_「正点原子Linux连载」第六十二章Linux SPI驱动实验(一)...
1)实验平台:正点原子Linux开发板 2)摘自<正点原子I.MX6U嵌入式Linux驱动开发指南>关注官方微信号公众号,获取更多资料:正点原子 第六十二章Linux SPI驱动实验 上一 ...
- Linux spi驱动分析(四)----SPI设备驱动(W25Q32BV)
一.W25Q32BV芯片简介 W25X是一系列SPI接口Flash芯片的简称,它采用SPI接口和CPU通信,本文使用的W25Q32BV容量为32M,具体特性如下: 1.1.基本特性 该芯片最大支持10 ...
- Linux spi驱动分析----SPI设备驱动(W25Q32BV)
转载地址:http://blog.chinaunix.net/uid-25445243-id-4026974.html 一.W25Q32BV芯片简介 W25X是一系列SPI接口Flash芯片的简称,它 ...
最新文章
- Linux内存技术分析(下)
- ASP.NET 2.0中GRIDVIEW排序
- 文件翻译002片:Process Monitor帮助文档(Part 2)
- linux——管理系统存储之设备的识别、发现、挂载
- 《2020总结-2021展望》
- 专利交底书模板_工大知识产权周 | 不说套话,看完这篇get专利技术交底书的要点!...
- reactjs npm start运行报错:Error: ENOSPC: System limit for number of file watchers reached
- How does framework require TechnicalInfo.js
- python正则表达式使用
- caffeine 淘汰策略
- Common Macros for Build Commands and Properties
- GridView常用代码 (转)
- Linux-1:安装忘记密码CRT连接centos 6.5
- Leetcode 79.单词搜索
- Ubuntu 下J2EE开发环境搭建
- 你做不到对企业真正有价值,下一个裁员就是你
- 网络规划设计师水平考试备考资料(11.分析总结)
- jmail 发送html,如何利用Jmail组件在线发送邮件
- C#可用的RSA公钥加密私钥解密以及私钥加密公钥解密,支持2048
- 怎样用计算机10,win10计算器怎么用_win10如何打开计算器