一、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数码管显示相关推荐

  1. i.MX6ULL驱动开发 | 14 - 基于 Linux SPI 驱动框架读取ICM-20608传感器

    本系列文章驱动源码仓库,欢迎Star~ https://github.com/Mculover666/linux_driver_study. 一.ICM20608 1. 简介 InvenSense 的 ...

  2. Linux SPI驱动框架(2)——控制器驱动层

    SPI控制器驱动层   上节中,讲了SPI核心层的东西,这一部分,以全志平台SPI控制器驱动为例,对SPI控制器驱动进行说明. SPI控制器驱动,即SPI硬件控制器对应的驱动,核心部分需要实现硬件SP ...

  3. Linux SPI驱动学习——调用SPI读写函数

    Linux SPI驱动学习--调用SPI读写函数 博客说明 开发环境 1. 基于W25Q16型FLASH来看SPI的读写函数 附录 博客说明 撰写日期 2019.10.25 完稿日期 未完稿 最近维护 ...

  4. Linux SPI驱动框架(3)——设备驱动层

    SPI设备驱动层   Linux SPI驱动框架(1)和(2)中分别介绍了SPI框架中核心层,和控制器驱动层.其实实际开发过程中,不是IC原厂工程师比较少会接触控制器驱动层,设备驱动层才是接触比较多的 ...

  5. i.MX6ULL驱动开发 | 13 - Linux SPI 驱动框架

    Linux SPI 驱动框架分为两部分: SPI总线控制器驱动:SOC的 SPI 控制器外设驱动 SPI设备驱动:基于SPI总线控制器驱动编写,针对具体的SPI从机设备 一.SPI总线控制器驱动 基于 ...

  6. linux spi不使用框架,Linux spi驱动框架之执行流程

    Linux spi驱动架构由三部分构成:SPI核心层.SPI控制器驱动层.和SPI设备驱动程序. 1.SPI核心层: SPI核心层是Linux的SPI核心部分,提供了核心数据结构的定义.SPI控制器驱 ...

  7. linux i2c adapter 增加设备_「正点原子Linux连载」第六十二章Linux SPI驱动实验(一)...

    1)实验平台:正点原子Linux开发板 2)摘自<正点原子I.MX6U嵌入式Linux驱动开发指南>关注官方微信号公众号,获取更多资料:正点原子 第六十二章Linux SPI驱动实验 上一 ...

  8. Linux spi驱动分析(四)----SPI设备驱动(W25Q32BV)

    一.W25Q32BV芯片简介 W25X是一系列SPI接口Flash芯片的简称,它采用SPI接口和CPU通信,本文使用的W25Q32BV容量为32M,具体特性如下: 1.1.基本特性 该芯片最大支持10 ...

  9. Linux spi驱动分析----SPI设备驱动(W25Q32BV)

    转载地址:http://blog.chinaunix.net/uid-25445243-id-4026974.html 一.W25Q32BV芯片简介 W25X是一系列SPI接口Flash芯片的简称,它 ...

最新文章

  1. Linux内存技术分析(下)
  2. ASP.NET 2.0中GRIDVIEW排序
  3. 文件翻译002片:Process Monitor帮助文档(Part 2)
  4. linux——管理系统存储之设备的识别、发现、挂载
  5. 《2020总结-2021展望》
  6. 专利交底书模板_工大知识产权周 | 不说套话,看完这篇get专利技术交底书的要点!...
  7. reactjs npm start运行报错:Error: ENOSPC: System limit for number of file watchers reached
  8. How does framework require TechnicalInfo.js
  9. python正则表达式使用
  10. caffeine 淘汰策略
  11. Common Macros for Build Commands and Properties
  12. GridView常用代码 (转)
  13. Linux-1:安装忘记密码CRT连接centos 6.5
  14. Leetcode 79.单词搜索
  15. Ubuntu 下J2EE开发环境搭建
  16. 你做不到对企业真正有价值,下一个裁员就是你
  17. 网络规划设计师水平考试备考资料(11.分析总结)
  18. jmail 发送html,如何利用Jmail组件在线发送邮件
  19. C#可用的RSA公钥加密私钥解密以及私钥加密公钥解密,支持2048
  20. 怎样用计算机10,win10计算器怎么用_win10如何打开计算器

热门文章

  1. 陈力:传智播客古代 珍宝币 泡泡龙游戏开发第十五讲:HTML教程笔记
  2. WPF Visifire 入门-动态曲线图
  3. TRIZ普及热潮有望到来
  4. PXE工作原理(有图有真相)
  5. 使用Gitee+Hexo搭建高速稳定的个人博客
  6. 搜索中常见数据结构与算法探究(一)
  7. 计算机网络ppt课件教学视频教程,计算机网络高级教程ppt课件
  8. 开一家水果店需要哪些设备,开水果店需要的设备有哪些
  9. 图像融合遇见Transformer
  10. Android开发 WebSocket