若该文为原创文章,转载请注明原文出处。
前面有测试过W25Q64,但那是自己编写的驱动,现在使用内核自带的驱动,只需要通过SPI标准接口,编写应用程序即可以读写W25Q64.
一、硬件原理图
SPI | 引脚 | 功能 |
---|---|---|
MOSI | GPIO3_C1 | 主设备输出/从设备输入 |
MISO | GPIO3_C2 | 主设备输入/从设备输出 |
CLOCK | CPIO3_C3 | 时钟信号线 |
CS0 | GPIO3_A1 | 片选信号线0 |
CS1 | NC | 片选信号线1 |
二、内核和设备树配置
1、内核支持
进入kenel目录,make menuconfig
具体路径如下所示:
> Device Drivers
> SPI support
2、设备树配置
修改/home/alientek/rk3568_linux_sdk/kernel/arch/arm64/boot/dts/rockchip/目录下的rk3568-atk-evb1-ddr4-v10.dtsi文件,在文件末添加代码,在spi1设备树下添加w25q64节点。
修改完成以后,重新编译一下内核,并烧写boot.img文件
重启板子后,查询,可以看到spidev1.0,其中1是spi1,0是cs0
至此驱动已经完成,前面有测试过回环测试,在那基础上修改程序。
三、测试程序
w25q64App.c
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <linux/spi/spidev.h>
#define SPI_DEV_PATH "/dev/spidev1.0"
int fd = 0; // SPI 控制引脚的设备文件描述符
static unsigned mode = SPI_MODE_0; //用于保存 SPI 工作模式
static uint8_t bits = 8; // 接收、发送数据位数
static uint32_t speed = 10000000; // 发送速度
static uint16_t delay = 0; //保存延时时间
#define W25X_JedecDeviceID 0x9F
#define Dummy_Byte 0xFF
void transfer(int fd, uint8_t const *tx, uint8_t const *rx, size_t len)
{
int ret;
struct spi_ioc_transfer tr = {
.tx_buf = (unsigned long)tx,
.rx_buf = (unsigned long)rx,
.len = len,
.delay_usecs = delay,
.speed_hz = speed,
.bits_per_word = bits,
.tx_nbits = 1,
.rx_nbits = 1
};
ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
if (ret < 1)
printf("can't send spi message\n");
}
void spi_init(int fd)
{
int ret = 0;
// spi mode 设置SPI 工作模式
ret = ioctl(fd, SPI_IOC_WR_MODE32, &mode);
if (ret == -1)
printf("can't set spi mode\n");
// bits per word 设置一个字节的位数
ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
if (ret == -1)
printf("can't set bits per word\n");
// max speed hz 设置SPI 最高工作频率
ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
if (ret == -1)
printf("can't set max speed hz\n");
// 打印
printf("spi mode: 0x%x\n", mode);
printf("bits per word: %d\n", bits);
printf("max speed: %d Hz (%d KHz)\n", speed, speed / 1000);
}
unsigned long SPI_FLASH_ReadID()
{
unsigned char tx_buffer[4] = {W25X_JedecDeviceID, Dummy_Byte, Dummy_Byte, Dummy_Byte};
unsigned char rx_buffer[4];
transfer(fd, tx_buffer, rx_buffer, sizeof(tx_buffer));
return (rx_buffer[1] << 16) | (rx_buffer[2] << 8) | rx_buffer[3];
}
int main(int argc, char *argv[])
{
unsigned long FlashID = 0x00000000;
if(argc < 2){
printf("Wrong use !!!!\n");
printf("Usage: %s [dev]\n",argv[0]);
return -1;
}
/*打开 SPI 设备*/
fd = open(argv[1], O_RDWR); // open file and enable read and write
if (fd < 0){
printf("Can't open %s \n",argv[1]); // open i2c dev file fail
exit(1);
}
/*初始化SPI */
spi_init(fd);
FlashID = SPI_FLASH_ReadID();
printf("Flash ID: 0x%08x\n", FlashID);
close(fd);
return 0;
}
程序只是简单的读取ID,要注意数据不能分开传,原因未知,像STM32传4次读不到ID。
如果有人知道,麻烦告知,谢谢。
接下来简单了,编写测试。
编译
/opt/atk-dlrk356x-toolchain/bin/aarch64-buildroot-linux-gnu-gcc w25q64App.c -o w25q64App
测试
测试前需要保证线是接好的,把生成的可执行文件上传到开发板。
测试正常读取到Flash的ID。
如有侵权,或需要完整代码,请及时联系博主。