当前位置: 首页 > news >正文

湘潭做网站出色磐石网络变量命名网站

湘潭做网站出色磐石网络,变量命名网站,制作网站的收入来源于哪里,证券公司网站建设方案瑞芯微RK3568芯片是一款定位中高端的通用型SOC#xff0c;采用22nm制程工艺#xff0c;搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码#xff0c;支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU#xff0c;可用于轻量级人工…瑞芯微RK3568芯片是一款定位中高端的通用型SOC采用22nm制程工艺搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU可用于轻量级人工智能应用。RK3568 支持安卓 11 和 linux 系统主要面向物联网网关、NVR 存储、工控平板、工业检测、工控盒、卡拉 OK、云终端、车载中控等行业。 ​ 【公众号】迅为电子 【粉丝群】258811263加群获取驱动文档例程 【视频观看】嵌入式学习之Linux驱动第十六篇 SPI_全新升级_基于RK3568 【购买链接】迅为RK3568开发板瑞芯微Linux安卓鸿蒙ARM核心板人工智能AI主板 第192章 mcp2515驱动编写完善write和read函数 在上个章节中对mcp2515的工作模式进行了修改从配置模式修改为了环回模式而在本章节将会继续对mcp2515的驱动程序进行完善加入mcp2515的写函数和读函数从而实现数据的发送和接收。 192.1 编写mcp2515写函数 MCP2515有三个发送缓冲器每个发送缓冲器都具有14字节的内存空间每个发送缓冲器的控制由TXBnCTRL寄存器管理该寄存器决定了何时发送报文以及发送时的报文状态。该寄存器的具体内容如下所示 需要通过该寄存器将缓冲器优先级设置为最高缓冲器优先级由bit1-0两位所决定当设置为11时该发送缓冲器具有最高的发送优先级可以通过以下代码进行设置 #define TXB0CTRL 0x30 //发送缓冲器控制寄存器地址 mcp2515_change_regbit(TXB0CTRL, 0x03, 0x03); //只对该寄存器低两位进行修改修改值为0x03 发送缓冲器控制寄存器TXBnCTRL为发送缓冲器的第一个字节接下来的5个字节用来装载标准和扩展标识符以及其他报文仲裁信息。最后的8个字节用于装载等待发送报文的8个可能的数据字节这13个字节数据由用户空间所传递且地址是连续的间隔为一个字节所以可以通过以下代码进行设置 char w_kbuf[13] {0}; int ret;// 从用户空间复制数据到内核缓冲区 ret copy_from_user(w_kbuf, buf, size); if (ret) {printk(copy_from_user w_kbuf is error\n);return -1; }// 将数据写入MCP2515寄存器 for (i 0; i sizeof(w_kbuf); i) {mcp2515_write_reg(0x31 i, w_kbuf[i]); } 数据设置完成之后需要将TXBnCTRL寄存器的bit3设置为1从而启动相应缓冲器的报文发送TXBnCTRL寄存器就是上面修改发送缓冲器优先级的寄存器具体设置代码如下所示 #define TXB0CTRL 0x30 //发送缓冲器控制寄存器地址 mcp2515_change_regbit(TXB0CTRL, 0x08, 0x08); //只对该寄存器bit3进行修改将bit3设置为1 在报文发送成功后CANINTF.TXnIF寄存器将会被置1该寄存器内容如下所示 可以通过该寄存器来判断报文是否发送成功由于使用的是缓冲器为0所以这里要判断的位位bit2判断完成之后需要对该寄存器进行手动清零具体判断代码如下所示 #define CANINTF 0x2c // 等待发送完成 while (!(mcp2515_read_reg(CANINTF) (1 2)));// 清除发送完成标志 mcp2515_change_regbit(CANINTF, 0x04, 0x00); 至此关于mcp2515写函数的相关知识就总结完成了可以将上面讲解的代码整理成一个完整的函数具体内容如下所示 #define TXB0CTRL 0x30 //发送缓冲器控制寄存器地址 #define CANINTF 0x2c // 写设备操作函数 ssize_t mcp2515_write(struct file *file, const char __user *buf, size_t size, loff_t *offset) {char w_kbuf[13] {0};int ret;int i;// 设置TXB0CTRL寄存器的部分位mcp2515_change_regbit(TXB0CTRL, 0x03, 0x03);// 从用户空间复制数据到内核缓冲区ret copy_from_user(w_kbuf, buf, size);if (ret) {printk(copy_from_user w_kbuf is error\n);return -1;}// 将数据写入MCP2515寄存器for (i 0; i sizeof(w_kbuf); i) {mcp2515_write_reg(0x31 i, w_kbuf[i]);}// 设置TXB0CTRL寄存器的部分位启动发送mcp2515_change_regbit(TXB0CTRL, 0x08, 0x08);// 等待发送完成while (!(mcp2515_read_reg(CANINTF) (1 2)));// 清除发送完成标志mcp2515_change_regbit(CANINTF, 0x04, 0x00);return size; } 192.2编写mcp2515读函数 在上个小节中编写了mcp2515的写函数在本小节将编写mcp2515的读函数。 MCP2515 具有两个全接收缓冲器当数据报文传送至某一接收缓冲器时与该接收缓冲器对应的CANINTF.RXnIF位将置1可以通过CANINTF.RXnIF寄存器的值来判断是否接收完成CANINTF寄存器内容在上一节已经列出这里不再重复具体判断代码如下所示 #define CANINTF 0x2c // 等待接收缓冲区满标志位被设置 while (!(mcp2515_read_reg(CANINTF) (1 0))); 然后编写读数据相关的代码接收缓冲器与发送寄存器相匹配前5个字节用来装载标准和扩展标识符以及其他报文仲裁信息最后的8个字节用于装载等待发送报文的8个可能的数据字节且地址是连续的间隔为一个字节接收缓冲器0的标准标识符高位寄存器地址为0x61所以可以通过以下代码进行设置 char r_kbuf[13] {0}; // 内核缓冲区用于存储从设备读取的数据int i;// 从接收缓冲区读取数据到内核缓冲区for (i 0; i sizeof(r_kbuf); i) {r_kbuf[i] mcp2515_read_reg(0x61 i);} 数据传送完成之后需要对CANINTF.RXnIF寄存器清零并且使用copy_to_user传输到用户空间具体代码如下所示 // 清除接收缓冲区满标志位mcp2515_change_regbit(CANINTF, 0x01, 0x00);// 将内核缓冲区的数据复制到用户缓冲区ret copy_to_user(buf, r_kbuf, size);if (ret) {printk(copy_to_user r_kbuf is error\n);return -1; // 返回-1表示复制数据失败} 至此关于mcp2515读函数的相关知识就总结完成了可以将上面讲解的代码整理成一个完整的函数具体内容如下所示 #define CANINTF 0x2c // 读设备操作函数从设备读取数据到用户缓冲区 ssize_t mcp2515_read(struct file *file, char __user *buf, size_t size, loff_t *offset) {char r_kbuf[13] {0}; // 内核缓冲区用于存储从设备读取的数据int i;int ret;// 等待接收缓冲区满标志位被设置while (!(mcp2515_read_reg(CANINTF) (1 0)));// 从接收缓冲区读取数据到内核缓冲区for (i 0; i sizeof(r_kbuf); i) {r_kbuf[i] mcp2515_read_reg(0x61 i);}// 清除接收缓冲区满标志位mcp2515_change_regbit(CANINTF, 0x01, 0x00);// 将内核缓冲区的数据复制到用户缓冲区ret copy_to_user(buf, r_kbuf, size);if (ret) {printk(copy_to_user r_kbuf is error\n);return -1; // 返回-1表示复制数据失败}return 0; // 返回0表示成功读取数据 } 192.3 实验程序编写 192.3.1 编写驱动程序 本实验驱动对应的网盘路径为iTOP-3568开发板\03_【iTOP-RK3568开发板】指南教程\02_Linux驱动配套资料\04_Linux驱动程序\118_mcp2515_06\。 本实验将以191章编写完成的驱动程序为基础添加了本章节完善的mcp2515的读和写函数编写完成的mcp2515.c代码如下所示 #include linux/init.h #include linux/module.h #include linux/spi/spi.h #include linux/cdev.h #include linux/fs.h #include linux/kdev_t.h #include linux/uaccess.h#define CNF1 0x2a // 寄存器定义 #define CNF2 0x29 #define CNF3 0x28 #define RXB0CTRL 0x60 #define CANINTE 0x2b #define CANCTRL 0xf // CAN控制寄存器#define TXB0CTRL 0x30 //发送缓冲器控制寄存器地址 #define CANINTF 0x2c dev_t dev_num; // 设备号 struct cdev mcp2515_cdev; // 字符设备结构体 struct class *mcp2515_class; // 设备类 struct device *mcp2515_device; // 设备 struct spi_device *spi_dev; // SPI设备指针// MCP2515芯片复位函数 void mcp2515_reset(void){int ret;char write_buf[] {0xc0}; // 复位指令0x11000000即0xc0ret spi_write(spi_dev, write_buf, sizeof(write_buf)); // 发送复位命令if(ret 0){printk(spi_write is error\n); // 打印错误信息} }// MCP2515读寄存器函数 char mcp2515_read_reg(char reg) {char write_buf[] {0x03, reg}; // SPI写缓冲区写入SPI读指令0x03char read_buf; // SPI读缓冲区int ret;ret spi_write_then_read(spi_dev, write_buf, sizeof(write_buf), read_buf, sizeof(read_buf)); // 调用SPI写读函数if (ret 0) {printk(spi_write_then_read error\n);return ret;}return read_buf; }// MCP2515写寄存器函数 void mcp2515_write_reg(char reg, char value) {int ret;char write_buf[] {0x02, reg, value}; // SPI写缓冲区用于发送写寄存器命令ret spi_write(spi_dev, write_buf, sizeof(write_buf)); // 发送SPI写命令if (ret 0) {printk(mcp2515_write_reg error\n);} }// MCP2515修改寄存器位函数 void mcp2515_change_regbit(char reg, char mask, char value) {int ret;char write_buf[] { 0x05, reg, mask, value }; // SPI写缓冲区用于发送修改寄存器位命令ret spi_write(spi_dev, write_buf, sizeof(write_buf)); // 发送SPI写命令if (ret 0) {printk(mcp2515_change_regbit error\n);} }// 打开设备文件的回调函数 int mcp2515_open(struct inode *inode, struct file *file) {return 0; // 返回成功 }// 读设备操作函数从设备读取数据到用户缓冲区 ssize_t mcp2515_read(struct file *file, char __user *buf, size_t size, loff_t *offset) {char r_kbuf[13] {0}; // 内核缓冲区用于存储从设备读取的数据int i;int ret;// 等待接收缓冲区满标志位被设置while (!(mcp2515_read_reg(CANINTF) (1 0)));// 从接收缓冲区读取数据到内核缓冲区for (i 0; i sizeof(r_kbuf); i) {r_kbuf[i] mcp2515_read_reg(0x61 i);}// 清除接收缓冲区满标志位mcp2515_change_regbit(CANINTF, 0x01, 0x00);// 将内核缓冲区的数据复制到用户缓冲区ret copy_to_user(buf, r_kbuf, size);if (ret) {printk(copy_to_user r_kbuf is error\n);return -1; // 返回-1表示复制数据失败}return 0; // 返回0表示成功读取数据 }// 写设备操作函数 ssize_t mcp2515_write(struct file *file, const char __user *buf, size_t size, loff_t *offset) {char w_kbuf[13] {0};int ret;int i;// 设置TXB0CTRL寄存器的部分位mcp2515_change_regbit(TXB0CTRL, 0x03, 0x03);// 从用户空间复制数据到内核缓冲区ret copy_from_user(w_kbuf, buf, size);if (ret) {printk(copy_from_user w_kbuf is error\n);return -1;}// 将数据写入MCP2515寄存器for (i 0; i sizeof(w_kbuf); i) {mcp2515_write_reg(0x31 i, w_kbuf[i]);}// 设置TXB0CTRL寄存器的部分位启动发送mcp2515_change_regbit(TXB0CTRL, 0x08, 0x08);// 等待发送完成while (!(mcp2515_read_reg(CANINTF) (1 2)));// 清除发送完成标志mcp2515_change_regbit(CANINTF, 0x04, 0x00);return size; }// 关闭设备文件的回调函数 int mcp2515_release(struct inode *inode, struct file *file) {return 0; // 返回成功 }// 设备文件操作集合 struct file_operations mcp2515_fops {.open mcp2515_open,.read mcp2515_read,.write mcp2515_write,.release mcp2515_release, };// MCP2515设备初始化函数 int mcp2515_probe(struct spi_device *spi) {int ret, value;printk(This is mcp2515_probe\n);spi_dev spi; // 保存SPI设备指针// 分配字符设备号ret alloc_chrdev_region(dev_num, 0, 1, mcp2515);if (ret 0) {printk(alloc_chrdev_region error\n);}// 初始化字符设备cdev_init(mcp2515_cdev, mcp2515_fops);mcp2515_cdev.owner THIS_MODULE;// 添加字符设备ret cdev_add(mcp2515_cdev, dev_num, 1);if (ret 0) {printk(cdev_add error\n);return -1;}// 创建设备类mcp2515_class class_create(THIS_MODULE, spi_to_can);if (IS_ERR(mcp2515_class)) {printk(mcp2515_class error\n);return PTR_ERR(mcp2515_class);}// 创建设备mcp2515_device device_create(mcp2515_class, NULL, dev_num, NULL, mcp2515);if (IS_ERR(mcp2515_device)) {printk(mcp2515_device error\n);return PTR_ERR(mcp2515_device);}mcp2515_reset(); // 复位MCP2515设备value mcp2515_read_reg(0x0e); // 读取寄存器值printk(value is %x\n, value); // 打印读取的值mcp2515_write_reg(CNF1, 0x01); // 写入寄存器配置值mcp2515_write_reg(CNF2, 0xb1);mcp2515_write_reg(CNF3, 0x05);mcp2515_write_reg(RXB0CTRL, 0x60);mcp2515_write_reg(CANINTE, 0x05);mcp2515_change_regbit(CANCTRL, 0xe0, 0x40);value mcp2515_read_reg(0x0e); // 读取寄存器值printk(value is %x\n, value); // 打印读取的值return 0; // 返回成功 }// MCP2515 SPI设备的移除函数 static int mcp2515_remove(struct spi_device *spi) {device_destroy(mcp2515_class, dev_num);class_destroy(mcp2515_class);cdev_del(mcp2515_cdev);unregister_chrdev_region(dev_num, 1);return 0; }// MCP2515设备匹配表,用于设备树匹配 static const struct of_device_id mcp2515_of_match_table[] {{ .compatible my-mcp2515 },{} };// MCP2515设备ID匹配表,用于总线匹配 static const struct spi_device_id mcp2515_id_table[] {{ mcp2515, 0 },{} };// MCP2515 SPI驱动结构体 static struct spi_driver spi_mcp2515 {.probe mcp2515_probe, // 探测函数.remove mcp2515_remove, // 移除函数.driver {.name mcp2515, // 驱动名称.owner THIS_MODULE, // 所属模块.of_match_table mcp2515_of_match_table, // 设备树匹配表 },.id_table mcp2515_id_table, // 设备ID匹配表 };// 驱动初始化函数 static int __init mcp2515_init(void) {int ret;// 注册SPI驱动ret spi_register_driver(spi_mcp2515);if (ret 0) {// 注册失败,打印错误信息printk(spi_register_driver error\n);return ret;}return ret; }// 驱动退出函数 static void __exit mcp2515_exit(void) {// 注销SPI驱动spi_unregister_driver(spi_mcp2515); }module_init(mcp2515_init); module_exit(mcp2515_exit);MODULE_LICENSE(GPL); 192.3.2 编写测试APP 本实验测试APP对应的网盘路径为iTOP-3568开发板\03_【iTOP-RK3568开发板】指南教程\02_Linux驱动配套资料\04_Linux驱动程序\118_mcp2515_06\。 #include stdio.h #include sys/types.h #include sys/stat.h #include fcntl.h #include unistd.h// 主函数程序入口点 int main(int argc, char *argv[]){int fd; // 文件描述符int i; // 循环变量// 写缓冲区包含13个字节的数据将发送到MCP2515char w_buf[13] {0x66,0x08,0x22,0x33,0x08,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08};// 读缓冲区用于接收从MCP2515读取的数据char r_buf[13] {0};// 打开MCP2515设备文件获取文件描述符fd open(/dev/mcp2515, O_RDWR);if(fd 0){// 打开设备文件失败打印错误信息并返回printf(open /dev/mcp2515 error \n);return -1;}// 将写缓冲区的数据写入设备write(fd, w_buf, sizeof(w_buf));// 从设备读取数据到读缓冲区read(fd, r_buf, sizeof(r_buf));// 打印读缓冲区的数据for(i 0; i 13; i){printf(r_buf[%d] is %d\n, i, r_buf[i]);}// 关闭设备文件close(fd);return 0; // 返回0表示程序正常结束 } 上述测试app代码中第13行表示要发送给mcp2515的13个字节的数据其中前5个字节用来装载标准和扩展标识符以及其他报文仲裁信息最后的8个字节用于装载等待发送报文的8个可能的数据字节第一个字节发送缓冲器标准标识符高位、第三个字节发送缓冲器扩展标识符高位、第四个字节发送缓冲器扩展标识符低位可以随意设置这里设置的是0x66、0x22、0x33。 第二个字节为发送缓冲器标准标识符低位该寄存器的具体内容如下所示 其中bit3代表扩展标识符的使能位这里需要设置为1进行使能换算成16进制为0x08。 第5个字节为发送缓冲器数据长度码该寄存器内容如下所示 其中bit6需要设置为0表示发送的报文为数据帧。而要发送的数据为8个字节所以bit3-bit0需要设置为8换算成16进制为0x08。 至此关于前5个字节内容的设置就讲解完成了而后8个字节为要发送的数据这里随意取值即可。 192.4 运行测试 192.4.1 编译驱动程序 在上一小节中的mcp2515.c代码同一目录下创建 Makefile 文件Makefile 文件内容如下所示 export ARCHarm64#设置平台架构 export CROSS_COMPILEaarch64-linux-gnu-#交叉编译器前缀 obj-m mcp2505.o #此处要和你的驱动源文件同名 KDIR :/home/topeet/Linux/linux_sdk/kernel #这里是你的内核目录 PWD ? $(shell pwd) all:make -C $(KDIR) M$(PWD) modules #make操作 clean:make -C $(KDIR) M$(PWD) clean #make clean操作 对于Makefile的内容注释已在上图添加保存退出之后来到存放mcp2515.c和Makefile文件目录下如下图所示 然后使用命令“make”进行驱动的编译编译完成如下图所示 编译完生成ft5x06_driver.ko目标文件如下图所示 至此驱动模块就编译成功了。 192.4.2 编译应用程序 首先进行应用程序的编译因为测试APP是要在开发板上运行的所以需要aarch64-linux-gnu-gcc来编译输入以下命令编译完成以后会生成一个app的可执行程序如下图所示 aarch64-linux-gnu-gcc app.c -o app 然后将编译完成的可执行程序拷贝到开发板上. 192.4.2 运行测试 在进行实验之前首先要确保开发板烧写的是我们在186.1小节中编译出来的boot.img。开发板启动之后然后使用以下命令进行驱动模块的加载如下图所示 insmod mcp2515.ko 然后使用“./app”运行上一小节中编译的可执行程序运行结果如下所示 可以看到可执行程序运行之后会将传输的13位数据依次打印出来这里打印的是10进制换算成16进制之后与0x66,0x08,0x22,0x33,0x08,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08相匹配证明编写的mcp2515读函数和写函数可以正常工作。 最后使用以下命令进行驱动模块的卸载如下图所示 rmmod mcp2515.ko 由于没有在remove卸载函数中添加打印相关内容所以使用rmmod命令卸载驱动之后没有任何打印。 至此MCP2515读函数和写函数测试实验就完成了。
http://www.hkea.cn/news/14575389/

相关文章:

  • 张家界做旅游网站邢台网站建设设计制作
  • 网站制作案例图片外贸网页设计公司
  • 装修公司做网站好做吗扶贫网站建设
  • 保定专门做网站重庆必玩景点排名
  • 营销型外贸网站广州wordpress重新配置ftp
  • 笔记本做网站服务器报价单模板表格
  • 如何建设传奇网站西安市网站
  • 南县做网站网站备案号怎么看
  • 创世网站建设公司英文网站建设之后怎么推
  • 四川住房与城乡建设厅网站做谷歌seo要发大量文章吗
  • 画册封面设计seo如何建立优化网站
  • 国外设计网站排名站长网站后台
  • 单页面网站模板宁波制作网站企业有哪些
  • 怎么修改WordPress文件結構seo深圳网络推广
  • 韩顺平 开源网站昆明百度seo
  • 百度怎么制作网站教程详情页设计图片
  • 国内比较高端的设计网站微信群发布网站建设
  • 高校网站建设模板南京展厅设计装修
  • 网站建设要程序员吗开封网站开发公司
  • 基于php的网站开发英文文献网上做试卷的网站
  • wordpress 建站 搜索网站建设一般用什么编程
  • 网站建设的岗位叫什么定制企业网站多少钱
  • 南宁建筑网站网站建站模板
  • 潍坊有哪些网站网站开发是固定资产吗
  • 西安地区网站建设鞍山人才招聘网官网
  • 腾讯网网站网址手机网站开发指南
  • 文件外链生成网站wordpress 导航别名
  • 我本沉默传奇新开网站网页设计与制作软件有哪些
  • 网站建设淘宝模板php可以做网站吗
  • 网站建设导航滁州注册公司流程和费用