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

有关网站建设的文章句子设计中国展

有关网站建设的文章句子,设计中国展,廊坊做网站多少钱,广州新冠最新情况若该文为原创文章#xff0c;转载请注明原文出处。 一、SPI介绍 串行外设接口 (Serial Peripheral interface) 简称 SPI#xff0c;是一种高速的#xff0c;全双工#xff0c;同步的通信总线#xff0c;并 且在芯片的管脚上只占用四根线#xff0c;节约了芯片的管脚。 …若该文为原创文章转载请注明原文出处。 一、SPI介绍 串行外设接口 (Serial Peripheral interface) 简称 SPI是一种高速的全双工同步的通信总线并 且在芯片的管脚上只占用四根线节约了芯片的管脚。 而W25Q64是常见的串行闪存器件W25Q64将8M字节的容量分为128个块每个块大小为64K字节每个块又分为16个扇区每个扇区4K个字节。W25Q64的最小擦除单位为一个扇区也就是每次必须擦除4K个字节。所以这需要给W25Q64开辟一个至少4K的缓存区这样必须要求芯片有4K以上的SRAM才能有很好的操作。 W25Q64的擦写周期多达10W次可将数据保存达20年之久支持2.7~3.6V的电压支持标准的SPI还支持双输出/四输出的SPI最大SPI时钟可达80Mhz。 二、spi 基本知识 spi 总线都可以挂载多个设备spi 支持标准的一主多从全双工半双工通信等。 其中四根控制线 包括 • SCK时钟线数据收发同步 • MOSI数据线主设备数据发送、从设备数据接收 • MISO数据线从设备数据发送主设备数据接收 • NSS片选信号线 i2c 通过 i2c 设备地址选择通信设备而 spi 通过片选引脚选中要通信的设备。 spi 接口支持有多个片选引脚连接多个 SPI 从设备当然也可以使用外部 GPIO 扩展 SPI 设备的 数量这样一个 spi 接口可连接的设备数由片选引脚树决定。 • 如果使用 spi 接口提供的片选引脚spi 总线驱动会处理好什么时候选 spi 设备。 • 如果使用外部 GPIO 作为片选引脚需要我们在 spi 设备驱动中设置什么时候选中 spi。 (或者 在配置 SPI 时指定使用的片选引脚)。 通常情况下无特殊要求我们使用 spi 接口提供的片选引脚。 三、SPI时序 • 起始信号NSS 信号线由高变低 • 停止信号NSS 信号由低变高 • 数据传输在 SCK 的每个时钟周期 MOSI 和 MISO 同时传输一位数据高/低位传输没有硬 性规定 – 传输单位8 位或 16 位 – 单位数量允许无限长的数据传输 四、硬件原理分析 ATK-DLRK3568的外设IO有引出SPI1。 对应W25Q64接线如下 W25Q64引脚ATK-DLRK35681-CSGPIO3_A1   SPI1_CS0_M12-DOGPIO3_C2  SPI1_MISO_M13-WP3.3V4-GNDGND5-DIGPIO3_C1  SPI1_MOSI_M16-CLKGPIO3_C3  SPI1_CLK_M17-HOLDNC8-VCC3.3V 使用杜邦线链接确保接线正常。 五、创建设备节点 1、设备树节点 修改/home/alientek/rk3568_linux_sdk/kernel/arch/arm64/boot/dts/rockchip/目录下的rk3568-atk-evb1-ddr4-v10.dtsi文件在文件末添加代码在spi1设备树下添加w25q64节点。 spi1 {status okay;pinctrl-names default, high_speed;pinctrl-0 spi1m1_cs0 spi1m1_pins;pinctrl-1 spi1m1_cs0 spi1m1_pins_hs;// 向 spi1 节点追加 w25q64 设备节点w25q64: w25q640 {compatible yifeng,w25q64;reg 0; // 设置 reg 属性为 0, 表示 spi 连接到 spi1 的通道 0spi-max-frequency 24000000; // 设置 SPI 传输的最大频率wp-gpio gpio3 RK_PA1 GPIO_ACTIVE_HIGH;pinctrl-0 w25q64_wp; /*w25q64_cs; */}; };2、创建设备的 pinctrl 节点 修改/home/alientek/rk3568_linux_sdk/kernel/arch/arm64/boot/dts/rockchip/目录下的rk3568-pinctrl.dtsi文件在最后面增加节点 w25q64 {/omit-if-no-ref/w25q64_wp: w25q64-wp {rockchip,pins 3 RK_PA1 RK_FUNC_GPIO pcfg_pull_up;};};设备树修改完成以后在 SDK 顶层目录输入如下命令重新编译一下内核 # 指定 SDK 的板级配置文件 ./build.sh lunch # 编译内核 ./build.sh kernel 编译完成以后得到 boot.img, boot.img 就是编译出来的内核设备树打包在一起的文件 只需要重新烧写boot.img。 烧写完成以后启动开发板。Linux 启动成功以后进入到/proc/device-tree/目录中查看是否有节点 六、编写驱动 1、spi_drv.c #include linux/module.h//模块加载卸载函数 #include linux/kernel.h//内核头文件 #include linux/types.h//数据类型定义 #include linux/fs.h//file_operations结构体 #include linux/device.h//class_create等函数 #include linux/ioctl.h #include linux/kernel.h/*包含printk等操作函数*/ #include linux/of.h/*设备树操作相关的函数*/ #include linux/gpio.h/*gpio接口函数*/ #include linux/of_gpio.h #include linux/platform_device.h/*platform device*/ #include linux/spi/spi.h /*spi相关api*/ #include linux/delay.h /*内核延时函数*/ #include linux/slab.h /*kmalloc、kfree函数*/ #include linux/cdev.h/*cdev_init cdev_add等函数*/ #include asm/uaccess.h/*__copy_from_user 接口函数*/#include linux/moduleparam.h #include linux/iio/iio.h #include linux/iio/machine.h #include linux/iio/driver.h #include linux/iio/consumer.h #include linux/types.h #include linux/kernel.h #include linux/delay.h #include linux/ide.h #include linux/init.h #include linux/module.h #include linux/errno.h #include linux/gpio.h #include linux/cdev.h #include linux/device.h #include linux/of_gpio.h #include linux/semaphore.h #include linux/timer.h #include linux/irq.h #include linux/wait.h #include linux/poll.h #include linux/fs.h #include linux/fcntl.h #include linux/platform_device.h #include asm/uaccess.h #include asm/io.h#define DEVICE_NAME spi #define W25Qxx_PAGE_SIZE 256 /*页 大小256字节*/ #define W25QXX_SECTOR_SIZE 4096 /*扇区 大小4096*//*W25Qxx 指令*/ #define W25X_WriteEnable 0x06 #define W25X_WriteDisable 0x04 #define W25X_ReadStatusReg 0x05 #define W25X_WriteStatusReg 0x01 #define W25X_ReadData 0x03 #define W25X_FastReadData 0x0B #define W25X_FastReadDual 0x3B #define W25X_PageProgram 0x02 #define W25X_BlockErase 0xD8 #define W25X_SectorErase 0x20 #define W25X_ChipErase 0xC7 #define W25X_PowerDown 0xB9 #define W25X_ReleasePowerDown 0xAB #define W25X_DeviceID 0xAB #define W25X_ManufactDeviceID 0x90 #define W25X_JedecDeviceID 0x9F typedef struct {void *tx_buf;void *rx_buf;unsigned char cmd; //w25q64指令unsigned int address; //写入或者读取的地址unsigned int tx_len; //需要写入的字节数unsigned int rx_len; //需要读取的字节数}w25qxx_data_def;typedef struct {struct device_node *node;//设备树节点struct cdev cdev; //定义一个cdev结构体struct class *class; //创建一个w25q64类struct device *device; //创建一个w25q64设备 该设备是需要挂在w25q64类下面的int major; //主设备号dev_t dev_id;struct spi_device *spi; /*spi设备*/int cspin; /*片选脚*/int wppin;struct mutex lock;w25qxx_data_def data; }w25qxx_typdef;static w25qxx_typdef w25qxx_dev;//定义一个w25q64设备/*函数声明*/ static int w25qxx_read_bytes(w25qxx_typdef *w25q64,unsigned int address,unsigned char* buf,int count);static int w25q64_spi_read_write(w25qxx_typdef *w25q64) {struct spi_device *spi w25q64-spi;struct spi_transfer xfer[2];struct spi_message msg;int ret 0;unsigned char *buf,*readbuf;memset(xfer, 0, sizeof(xfer));/*必须清0 否则无法spi_sync函数无法发送数据*/xfer[0].tx_buf w25q64-data.tx_buf;xfer[0].len w25q64-data.tx_len;buf (unsigned char *)(w25q64-data.tx_buf);xfer[1].rx_buf w25q64-data.rx_buf;xfer[1].len w25q64-data.rx_len;spi_message_init(msg);spi_message_add_tail(xfer[0], msg);if(w25q64-data.rx_len){spi_message_add_tail(xfer[1], msg);}ret spi_sync(spi, msg); if(ret ! 0){ printk(spi_sync failed %d\n, ret);}readbuf (unsigned char *)(w25q64-data.rx_buf);return ret; }static void spi_wp_enable(void) {gpio_set_value(w25qxx_dev.wppin, 1); }static void spi_wp_disable(void) {gpio_set_value(w25qxx_dev.wppin, 0); }static void spi_cs_enable(void) {//gpio_set_value(w25qxx_dev.cspin, 0); /* cs 0 */ }static void spi_cs_disable(void) {//gpio_set_value(w25qxx_dev.cspin, 1); /* cs 1 */ }static void spi_write_enable(void) {int ret;unsigned char tx_buf[1];spi_cs_enable();tx_buf[0] W25X_WriteEnable;/*写使能指令*/w25qxx_dev.data.tx_buf tx_buf; w25qxx_dev.data.tx_len 1;w25qxx_dev.data.rx_len 0;ret w25q64_spi_read_write(w25qxx_dev);spi_cs_disable(); }static void spi_write_disable(void) {int ret;unsigned char tx_buf[1];spi_cs_enable();tx_buf[0] W25X_WriteDisable;/*写失能指令*/w25qxx_dev.data.tx_buf tx_buf; w25qxx_dev.data.tx_len 1;w25qxx_dev.data.rx_len 0;ret w25q64_spi_read_write(w25qxx_dev);spi_cs_disable(); }static int w25qxx_get_sr(w25qxx_typdef *w25q64) {int ret -EINVAL;unsigned char tx_buf[1];unsigned char rx_buf[1];spi_cs_enable();tx_buf[0] W25X_ReadStatusReg;w25q64-data.tx_buf tx_buf; w25q64-data.tx_len 1;w25q64-data.rx_buf rx_buf;w25q64-data.rx_len 1;ret w25q64_spi_read_write(w25q64);spi_cs_disable();if(ret 0){printk(w25qxx_get_sr failed \n);return ret;}return rx_buf[0]; }static int w25qxx_get_id(w25qxx_typdef *w25q64) {int ret -EINVAL;unsigned char tx_buf[4];unsigned char rx_buf[5];spi_cs_enable();tx_buf[0] W25X_ManufactDeviceID;/*读取ID指令*/tx_buf[1] 0x0;tx_buf[2] 0x0;tx_buf[3] 0x0;w25q64-data.tx_buf tx_buf; w25q64-data.tx_len 4;w25q64-data.rx_buf rx_buf;w25q64-data.rx_len 2;ret w25q64_spi_read_write(w25q64);spi_cs_disable();if(ret ! 0){printk(w25qxx_get_id failed %d\n,ret);return ret;}printk(rx_buf 0x%x 0x%x 0x%x 0x%x\n\r,rx_buf[0], rx_buf[1], rx_buf[2], rx_buf[3]);return (rx_buf[0] 8 | rx_buf[1]); }static void w25qxx_Reset(w25qxx_typdef *w25q64) {int ret -EINVAL;unsigned char tx_buf[4];//unsigned char rx_buf[5];//spi_wp_disable(); spi_cs_enable();udelay(2);tx_buf[0] 0x66;/*读取ID指令*/tx_buf[1] 0x99;w25q64-data.tx_buf tx_buf; w25q64-data.tx_len 2;w25q64-data.rx_buf rx_buf;w25q64-data.rx_len 0;ret w25q64_spi_read_write(w25q64);spi_cs_disable();spi_wp_enable();udelay(2);if(ret 0){printk(w25qxx_get_id failed %d\n,ret);}else{printk(w25qxx_ Init Success %d\n,ret); } }static int w25qxx_wait_idle(void) {int ret -EINVAL; do {ret w25qxx_get_sr(w25qxx_dev);if(ret 0 ){return ret;/*通信错误*/}else{if(!(ret 0x01)){return 0;/*w25q64空闲*/}} /* REVISIT: at HZ100, this is sloooow */msleep(10);} while(1); return 1; }static int w25qxx_erase_sector(w25qxx_typdef *w25q64,unsigned int address) {int ret -EINVAL;unsigned char tx_buf[4];//spi_write_enable();/*写保护关闭*/spi_cs_enable();tx_buf[0] W25X_SectorErase;/*扇区擦除指令*/tx_buf[1] (unsigned char)((address16) 0xFF);tx_buf[2] (unsigned char)((address8) 0xFF);tx_buf[3] (unsigned char)(address 0xFF);w25q64-data.tx_buf tx_buf; w25q64-data.tx_len 4;w25q64-data.rx_len 0;ret w25q64_spi_read_write(w25q64);spi_cs_disable();if(ret ! 0){printk(erase sector%d failed %d\n,address,ret);return ret;}ret w25qxx_wait_idle();/*等待flash内部操作完成*/spi_write_disable();/*写保护打开*/return ret; }static int w25qxx_erase_chip(w25qxx_typdef *w25q64) {int ret -EINVAL;unsigned char tx_buf[1];//spi_write_enable();/*写保护关闭*/spi_cs_enable();tx_buf[0] W25X_ChipErase;/*扇区擦除指令*/w25q64-data.tx_buf tx_buf; w25q64-data.tx_len 1;w25q64-data.rx_len 0;ret w25q64_spi_read_write(w25q64);spi_cs_disable();if(ret ! 0){printk(erase chip failed %d\n, ret);return ret;}ret w25qxx_wait_idle();/*等待flash内部操作完成*/spi_write_disable();/*写保护打开*/return ret; }static int w25qxx_need_erase(unsigned char*old,unsigned char*new,int count) {int i;unsigned char p;for ( i 0; i count; i){p *old;p ~p; if((p (*new))!0){return 1;}}return 0; }static int w25qxx_read_bytes(w25qxx_typdef *w25q64,unsigned int address,unsigned char* buf,int count) {int ret -EINVAL;unsigned char tx_buf[4];//spi_cs_enable();tx_buf[0] W25X_ReadData;/*读取数据指令*/tx_buf[1] (unsigned char)((address16) 0xFF);tx_buf[2] (unsigned char)((address8) 0xFF);tx_buf[3] (unsigned char)(address 0xFF);w25q64-data.tx_buf tx_buf; w25q64-data.tx_len 4;w25q64-data.rx_buf buf;w25q64-data.rx_len count;ret w25q64_spi_read_write(w25q64);spi_cs_disable();if(ret ! 0){printk(read%d ,%d bytes failed %d\n,address,count,ret);return ret;}return ret; }static int w25qxx_write_page(w25qxx_typdef *w25q64,unsigned int address,unsigned char* buf,int count) {int ret -EINVAL;unsigned char *tx_buf;/*数据缓冲区*/tx_buf (unsigned char*)kzalloc(count4,GFP_KERNEL);if(!tx_buf)return -ENOMEM;spi_write_enable();/*写保护关闭*/spi_cs_enable();tx_buf[0] W25X_PageProgram;/*页写指令*/tx_buf[1] (unsigned char)((address16) 0xFF);tx_buf[2] (unsigned char)((address8) 0xFF);tx_buf[3] (unsigned char)(address 0xFF);memcpy(tx_buf[4],buf,count);w25q64-data.tx_buf tx_buf; w25q64-data.tx_len count4;w25q64-data.rx_len 0;/*不需要读*///printk(tx_data:%d-%d-%d-%d,count%d\n,tx_buf[4],tx_buf[5],tx_buf[6],tx_buf[7],w25q64-data.tx_len);ret w25q64_spi_read_write(w25q64);spi_cs_disable();if(ret ! 0){printk(write page%d ,%d bytes failed %d\n,address,count,ret);kfree(tx_buf);spi_write_disable();/*写保护打开*/return ret;}ret w25qxx_wait_idle();kfree(tx_buf); spi_write_disable();/*写保护打开*/return ret; }static int w25qxx_write_pages(w25qxx_typdef *w25q64,unsigned int address,unsigned char* buf,int count) {int ret -EINVAL;unsigned int remain_of_page,need_to_write;unsigned int sector_first_address,sector_offset;unsigned char *write_buf;/*数据缓冲区*/write_buf (unsigned char*)kzalloc(4096,GFP_KERNEL);if(!write_buf)return -ENOMEM;/*获取指定地址所在扇区的扇区首地址*/ sector_first_address address (~(W25Qxx_PAGE_SIZE-1)) ;/*获取指定地址在所在扇区内的偏移量*/sector_offset address % 4096;ret w25qxx_read_bytes(w25q64,sector_first_address,write_buf,4096);//读出整个扇区if(ret 0 ){return ret;}/*判断是否需要擦除*/if(w25qxx_need_erase(write_buf[sector_offset],buf,count)){printk(erase\n);w25qxx_erase_sector(w25q64,sector_first_address);}kfree(write_buf);remain_of_page W25Qxx_PAGE_SIZE - address%W25Qxx_PAGE_SIZE;//获取本页还剩多少个字节空间可写入need_to_write remain_of_page;/*下一次最多可写remain_of_page个字节*/printk(sector_first_address%d,sector_offset%d\n,sector_first_address,sector_offset);printk(address%d,count%d\n,address,count);if(count need_to_write) {/*需要写入的字节数少于剩余空间 直接写入实际字节数*/ret w25qxx_write_page(w25q64,address,buf,count);return ret;}else{ do{printk(address%d\n,need_to_write%d\n,address,need_to_write); ret w25qxx_write_page(w25q64,address,buf,need_to_write);if(ret !0){return ret;}if(need_to_write count){break;}else{bufneed_to_write;addressneed_to_write;count-need_to_write; if(count W25Qxx_PAGE_SIZE){need_to_write W25Qxx_PAGE_SIZE;}else{need_to_write count;}} } while (1); }return ret; }static int w25qxx_write_more_bytes(w25qxx_typdef *w25q64,unsigned int address,unsigned char* buf,int count) {int ret -EINVAL;unsigned int num_of_sector,remain_of_sector,sector_offset;unsigned int need_to_write;//sector_first_addressunsigned char *write_buf;/*数据缓冲区*/write_buf (unsigned char*)kzalloc(4096,GFP_KERNEL);if(!write_buf)return -ENOMEM;num_of_sector address / W25QXX_SECTOR_SIZE;sector_offset address % W25QXX_SECTOR_SIZE;remain_of_sector W25QXX_SECTOR_SIZE - address % W25QXX_SECTOR_SIZE;/*当前地址所在扇区 还剩下多少空间*/need_to_write remain_of_sector;if(count need_to_write){ret w25qxx_write_pages(w25q64,address,buf,count);return ret;}else{do{ret w25qxx_write_pages(w25q64,address,buf,need_to_write);if(ret !0){return ret;}if(need_to_write count){break;}else{bufneed_to_write;addressneed_to_write;count-need_to_write; if(count W25QXX_SECTOR_SIZE){need_to_write W25QXX_SECTOR_SIZE;}else{need_to_write count;}} } while (1); }return ret; }static int w25qxx_open(struct inode *inode, struct file *filp) {filp-private_data w25qxx_dev;return 0; }static int w25qxx_release(struct inode* inode ,struct file *filp) {// w25qxx_typdef *dev (w25qxx_typdef *) filp-private_data;return 0; }static ssize_t w25qxx_write(struct file *filp, const char __user *buf, size_t count,loff_t *f_pos) { int ret; unsigned char *write_buf;/*数据缓冲区*/w25qxx_typdef * dev (w25qxx_typdef *) filp-private_data;unsigned char address filp-f_pos;write_buf (unsigned char*)kzalloc(count,GFP_KERNEL);if(!write_buf )return -ENOMEM;spi_wp_enable();if (copy_from_user(write_buf, buf, count)){kfree(write_buf);return -EFAULT;}printk(write %d,count %d\n, address, (int)count);ret w25qxx_write_more_bytes(dev,address,write_buf,count);spi_wp_disable();kfree(write_buf);return ret; }static ssize_t w25qxx_read(struct file *filp,char __user *buf, size_t count,loff_t *f_pos) {int ret; unsigned char *read_buf;/*数据缓冲区*/w25qxx_typdef * dev (w25qxx_typdef *) filp-private_data;unsigned char address filp-f_pos;read_buf (unsigned char*)kzalloc(count,GFP_KERNEL);if(!read_buf )return -ENOMEM;printk(read%d,count:%d\n,address, (int)count);ret w25qxx_read_bytes(dev,address,read_buf,count);if (copy_to_user(buf, read_buf, count)){ret -EFAULT;}kfree(read_buf);return ret; }loff_t w25qxx_llseek(struct file *file, loff_t offset, int whence) {loff_t ret,pos,oldpos;oldpos file-f_pos;switch (whence) {case SEEK_SET:pos offset; break;case SEEK_CUR:pos oldpos offset;break;case SEEK_END:pos W25Qxx_PAGE_SIZE - offset;break; default:printk(cmd not supported\n);break;}if(pos 0 || pos W25Qxx_PAGE_SIZE){ printk(error: pos W25Qxx_PAGE_SIZE !\n);ret -EINVAL;return ret;}file-f_pos pos;ret offset; return ret; }static struct file_operations w25qxx_fops{.owner THIS_MODULE,.open w25qxx_open,.write w25qxx_write,.read w25qxx_read,.release w25qxx_release,.llseek w25qxx_llseek, };static int w25qxx_probe(struct spi_device *spi) {int ret -1;const char *string NULL;w25qxx_typdef *dev w25qxx_dev;printk(w25q64 probe!\n); /*获取设备节点*/w25qxx_dev.node of_find_node_by_path(/spife620000/w25q640);if(w25qxx_dev.node NULL){printk(device-tree:not found w25q64!\r\n); return -1;}/*读取w25q64设备节点的compatible属性值*/ret of_property_read_string(w25qxx_dev.node,compatible,string);if(ret 0){printk(%s\n,string);}/*申请gpio 用作片选*/w25qxx_dev.wppin of_get_named_gpio(w25qxx_dev.node,wp-gpio,0);if(!gpio_is_valid(w25qxx_dev.wppin)){printk(get gpio error\n);ret -EINVAL;return ret;}printk(gpio %d\n,w25qxx_dev.wppin);ret gpio_request(w25qxx_dev.wppin,spi-wp);if(ret 0) {printk(gpio_request %d failed\n,w25qxx_dev.wppin);return ret;}gpio_direction_output(w25qxx_dev.wppin, 1);gpio_export(w25qxx_dev.wppin, 1);/*申请gpio 用作片选*/// w25qxx_dev.cspin of_get_named_gpio(w25qxx_dev.node,cs-gpios,0);// if(!gpio_is_valid(w25qxx_dev.cspin))// {// printk(get gpio error\n);// ret -EINVAL;// return ret;// }// printk(gpio %d\n,w25qxx_dev.cspin);// ret gpio_request(w25qxx_dev.cspin,spi-cs);// if(ret 0) // {// printk(gpio_request %d failed\n,w25qxx_dev.cspin);// return ret;// }// gpio_direction_output(w25qxx_dev.cspin, 1);// gpio_export(w25qxx_dev.cspin, 1);/*申请设备号*/alloc_chrdev_region(w25qxx_dev.dev_id,0,1,DEVICE_NAME);/*初始化一个cdev*/cdev_init(w25qxx_dev.cdev,w25qxx_fops);/*向cdev中添加一个设备*/cdev_add(w25qxx_dev.cdev,w25qxx_dev.dev_id,1);/*创建一个norflash_class类*/w25qxx_dev.class class_create(THIS_MODULE, norflash_class);if(w25qxx_dev.class NULL){printk(class_create failed\r\n);return -1;}/*在eeprom_class类下创建一个eeprom_class设备*/w25qxx_dev.device device_create(w25qxx_dev.class, NULL, w25qxx_dev.dev_id, NULL, DEVICE_NAME);/*获取与本驱动匹配的spi设备*/w25qxx_dev.spi spi;//w25qxx_dev.spi-mode SPI_MODE_3; /*spi flash对应的模式*/spi_setup(w25qxx_dev.spi);mutex_init(dev-lock);w25qxx_Reset(w25qxx_dev);mdelay(200);ret w25qxx_erase_chip(w25qxx_dev);if(ret 0){printk(w25qxx_erase_chip failed\r\n);} ret w25qxx_get_id(w25qxx_dev);printk(id%04x\n,ret);return 0; }static int w25qxx_remove(struct spi_device *spi) {printk(w25qxx remove!\n); /*删除w25q64类*/cdev_del(w25qxx_dev.cdev);/*释放w25q64设备号*/unregister_chrdev_region(w25qxx_dev.dev_id, 1);/*注销w25q64设备*/device_destroy(w25qxx_dev.class, w25qxx_dev.dev_id);/*注销w25q64类*/class_destroy(w25qxx_dev.class);gpio_free(w25qxx_dev.wppin);//gpio_free(w25qxx_dev.cspin);return 0; }static const struct of_device_id w25qxx_of_match[] {{.compatible yifeng,w25q64},{}, };static const struct spi_device_id w25q64_id[] {{ xxxx, 0 },{}, };static struct spi_driver w25qxx_driver {.driver {.owner THIS_MODULE,.name w25q64,.of_match_table w25qxx_of_match,},.probe w25qxx_probe,.remove w25qxx_remove, .id_table w25q64_id, };static int __init w25qxx_init(void) {printk(module init ok\n);return spi_register_driver(w25qxx_driver); }static void w25qxx_exit(void) {spi_unregister_driver(w25qxx_driver);printk(module exit ok\n); }module_init(w25qxx_init); module_exit(w25qxx_exit);MODULE_LICENSE(GPL); MODULE_DESCRIPTION(w25q64 driver); MODULE_AUTHOR(yifeng); 代码中获取设备节点需要注意 w25qxx_dev.node of_find_node_by_path(/spife620000/w25q640); 这里的/spife620000/w25q640需要先在开发板上确定。 片选引脚也需要指定。 2、makefile KERNELDIR : /home/alientek/rk3568_linux_sdk/kernel ARCHarm64 CROSS_COMPILE/opt/atk-dlrk356x-toolchain/usr/bin/aarch64-buildroot-linux-gnu-export ARCH CROSS_COMPILECURRENT_PATH : $(shell pwd) obj-m : spi_drv.obuild: kernel_moduleskernel_modules:$(MAKE) -C $(KERNELDIR) M$(CURRENT_PATH) modules clean:$(MAKE) -C $(KERNELDIR) M$(CURRENT_PATH) clean编译生成ko文件 七、应用程序编写 // APP应用 #include stdio.h #include stdlib.h #include unistd.h #include sys/types.h #include sys/stat.h #include fcntl.h #include termios.h #include errno.h #include limits.h #include asm/ioctls.h #include time.h #include pthread.h #includestring.h#define num 128void print_data(const char *title, char *dat, int count) {int i 0; printf(title);for(i 0; i count; i) {printf( 0x%x, dat[i]);}printf(\n); }int main(int argc, char *argv[]) {int fd,ret,i;int count num;int offset 0; char write_buf[num],read_buf[num];/*判断传入的参数是否合法*/if(argc ! 2){printf(Usage:error\n);return -1;}/*解析传入的参数*/offset atoi(argv[1]);printf(offset %d\n, offset);/*打开设备文件*/fd open(/dev/spi, O_RDWR);if(fd 0){printf(open dev fail fd%d\n,fd); close(fd);return fd;}/*缓存数组赋值*///memset(write_buf, 0x55, num);for(i 0; i num; i){write_buf[i] i;}/*写入数据*/ lseek(fd,offset,SEEK_SET);ret write(fd,write_buf,num);if(ret 0){printf(write to w25qxx error\n);close(fd);return ret;}/*打印数据*/print_data(write to w25qxx: \n\r, write_buf, count);/*读取数据*/ret lseek(fd,offset,SEEK_SET);printf(lseek %d\n,ret);ret read(fd, read_buf, count);if(ret 0){printf(read from w25qxx error\n);close(fd);return ret;}/*打印数据*/print_data(read from w25qxx: \n\r,read_buf, count);ret memcmp(write_buf, read_buf, count);if(ret){printf(Writing data is different from reading data...\n);}else{printf(Write data is the same as read data...\n);}close(fd);return 0; } 编译 /opt/atk-dlrk356x-toolchain/bin/aarch64-buildroot-linux-gnu-gcc spiApp.c -o spiApp 八、测试 测试比较简单写入128个数在读出来比较。 到此测试完成使用硬件SPI正常。 但有个疑问使用ret ioctl(fd, SPI_IOC_MESSAGE(1), tr);是怎么处理的留个问题。 如有侵权或需要完整代码请及时联系博主。
http://www.dnsts.com.cn/news/45025.html

相关文章:

  • 做心理咨询可以在哪些网站发贴1000元做网站
  • 成都网站建设 雷拍卖网站建设
  • 网站建设的方案实施包括网络平面设计是干什么
  • 新闻列表做的最好的网站wordpress 标签 修改
  • wordpress08影院404seo云优化
  • 品牌微信网站定制辽宁建设工程信息网 招标文件
  • 网站vr用什么做seo完整教程视频教程
  • 合肥公司做网站清远新闻最新
  • 一个微信公众号可以做几个网站电商网站建设开发的语言有哪些
  • 哪个网站有老外教做蛋糕263企业邮箱怎么修改密码
  • 重庆工程信息网查询百度优化关键词
  • 网站备案后经营黑帽seo排名技术
  • 个人网站做电影网站织梦模板 行业网站
  • 网站空间租用哪家好网络运营管理是做什么的
  • 互联网网站解决方案东莞龙舟制作技艺
  • 深圳 电子商务网站开发深圳市律师网站建设怎么样
  • 网站图片引导页怎么做西安网站制作资源
  • hyip系统网站开发抖音推广引流平台
  • 江门市智企互联网站建设魔客吧wordpress主题如何安装
  • 电子产品网站开发背景腾讯云网站搭建教程
  • 牛股大转盘网站建设关键词怎么提取
  • 上传图片的网站要怎么做xss wordpress script
  • 东莞网站推广及优化创意品牌型网站
  • 上海网站建设最好的公司No餐饮网站建设
  • 什么网站可以做pptwordpress wp_list_categories
  • 高端外贸网站建设黑龙江生产建设兵团知识网站
  • 网站 备案 中国 名字免费源码下载网站
  • 有固定ip自己做网站门户网站建设自查整改
  • 网站开发外包价格石家庄建站网页模板
  • 山东住房和城乡建设厅网站注册中心优秀手机网站版式