[立创泰山派]RK3566 添加内核的spi设备spidev3.0

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

SPI是一种常见的设备通用通信协议。它有一个独特优势就是可以无中断传输数据,可以连续地发送或接收任意数量的位。而在I2C和 UART 中,数据以数据包的形式发送,有着限定位数。


一、SPI的优缺点

优点
SPI通讯无起始位和停止位,因此数据可以连续流传输而不会中断;没有像 I2C这样的复杂的从站寻址系统,数据传输速率比I2c更高(几乎快两倍)。独立的MISO 和 MOSI 线路,可以同时发送和接收数据。
缺点
SPI使用四根线(I2C和 UART 使用两根线),没有信号接收成功的确认(I2C拥有此功能),没有任何形式的错误检查(如 UART 中的奇偶校验位等)。

二、SPI的属性

1.SPI的特点

1,spi是一种高速,全双工,同步串行总线
2,spi有主从两种模式,通常由一个主设备或者多个从设备组成。spi不支持多主机。
3,spi通信至少需要四根线,分别是:
MISO(M:即主设备,I:即输入,S:即从设备,O:即输入,所以就是主设备输入,从设备输出),
MOSI(同理,即主设备输出,从设备输入),
SCLK(时钟信号),
CS/C(片选信号)。

连接方式:
在这里插入图片描述
在这里插入图片描述

2.SPI的通信原理

在这里插入图片描述

3.SPI的极性和相位

分别是 CPOL(Clock POlarity)和CPHA(Clock PHAse)。

- CPOL配置SPI总线的极性
- CPHA配置SPI总线的相位

3.1 SPI总线的极性

极性,会直接影响SPI总线空闲时的时钟信号是高电平还是低电平。

- CPOL=1:表示空闲时是高电平
- CPOL=0:表示空闲时是低电平
在这里插入图片描述

3.2 SPI总线的相位

一个时钟周期会有2个跳变沿。而相位,直接决定SPI总线从那个跳变沿开始采样数据。

-CPHA=0:表示从第一个跳变沿开始采样
-CPHA =1:表示从第二个跳变沿开始采样

在这里插入图片描述

3.3 SPI的四种工作模式

在这里插入图片描述
模式0

CPoL = 0:空闲时是低电平,第1个跳变沿是上升沿,第2个跳变沿是下降沿
CPHA = 0:数据在第1个跳变沿(上升沿)采样

时序图

模式1

CPOL =0::空闲时是低电平,第1个跳变沿是上升沿,第2个跳变沿是下降沿
CPHA =1:数据在第2个跳变沿(下降沿)采样

在这里插入图片描述

模式2

CPOL = 1:空闲时是高电平,第1个跳变沿是下降沿,第2个跳变沿是上升沿
CPHA = 0:数据在第1个跳变沿(下降沿)采样

在这里插入图片描述

模式3

CPOL = 1:空闲时是高电平,第1个跳变沿是下降沿,第2个跳变沿是上升沿
CPHA = 1:数据在第2个跳变沿(上升沿)采样

在这里插入图片描述
四种模式总图
在这里插入图片描述

4.SPI的通信过程

SPI总线在进行数据传输的时候,默认先传输高位,后传输低位。数据线高电平表示逻辑1,数据线低电平表示逻辑0,一个字节传输完成后无需应答信号即可开启下一个字节的传输。
SPI总线采用同步方式,在时钟线的第一个或者第二个跳变沿采集数据(主机侧读数据),然后在紧接着下一个跳变沿发数据。8个时钟周期即可完成一个字节的数据传输。
模式0为例:
在这里插入图片描述

三、添加内核自带SPI设备节点

在tspi-rk3566-user-v10-linux.dts下添加如下内容

spi3: spi@fe640000 {
		compatible = "rockchip,rk3066-spi";
		reg = <0x0 0xfe640000 0x0 0x1000>;
		interrupts = <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>;
		#address-cells = <1>;
		#size-cells = <0>;
		clocks = <&cru CLK_SPI3>, <&cru PCLK_SPI3>;
		clock-names = "spiclk", "apb_pclk";
		dmas = <&dmac0 26>, <&dmac0 27>;
		dma-names = "tx", "rx";
		pinctrl-names = "default", "high_speed";
		pinctrl-0 = <&spi3m0_cs0 &spi3m0_cs1 &spi3m0_pins>;
		pinctrl-1 = <&spi3m0_cs0 &spi3m0_cs1 &spi3m0_pins_hs>;
		status = "disabled";
	};


&spi3{
  status = "okay";
  pinctrl-names = "default", "high_speed";
  //开启spi3,指定使用的pinctrl节点和cs片选引脚
  pinctrl-0 = <&spi3m1_cs0 &spi3m1_pins>;  
  pinctrl-1 = <&spi3m1_cs0 &spi3m1_pins_hs>;
  //cs-gpios = <&gpio4 RK_PC6 GPIO_ACTIVE_LOW>;

  spi_test@0 {
      status = "okay";
      compatible = "rockchip,spidev";
      reg = <0>;                        //chip select 0:cs0  1:cs1
      spi-max-frequency = <10000000>;   //spi output clock
      //dc_control_pin = <&gpio3 RK_PA7 GPIO_ACTIVE_HIGH>;
      pinctrl-names = "default";
      //pinctrl-0 = <&spi_oled_pin>;
  };
};

然后编译kernel烧录boot到开发板启动即可在 /dev/目录下看到spidev3.0这个设备
在这里插入图片描述

四、编译内核自带的spi工具进行测试

内核自带的SPI工具位于此目录下

SDK/kernel/tools/spi

在/kernel/tools/spi下,需要自己手动先make一下
在这里插入图片描述
在这里插入图片描述

接下来我们使用另外一个测试程序不使用官方这个,我们使用这个程序

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/spi/spidev.h>

#define SPI_DEV_PATH "/dev/spidev3.0" //修改为你要测试的SPI设备

int fd;
static unsigned mode = SPI_MODE_0;
static uint8_t bits = 8;
static uint32_t speed = 1000000; // 设置SPI速度为1MHz
static uint16_t delay;

void transfer(int fd, uint8_t const *tx, uint8_t *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,
        .cs_change = 0, // 设置为1以在每次传输前切换片选,这里不切换片选
    };

    ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);

    if (ret < 1) {
        perror("SPI transfer failed");
    }
}

void spi_init(void)
{
    int ret;
    // 打开 SPI 设备
    fd = open(SPI_DEV_PATH, O_RDWR);
    if (fd < 0) {
        perror("Can't open SPI device");
        exit(1);
    }

    // 设置 SPI 工作模式
    ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
    if (ret == -1) {
        perror("Can't set SPI mode");
        exit(1);
    }

    // 设置位数
    ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
    if (ret == -1) {
        perror("Can't set bits per word");
        exit(1);
    }

    // 设置SPI速度
    ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
    if (ret == -1) {
        perror("Can't set max speed");
        exit(1);
    }

    // 打印设置
    printf("SPI mode: 0x%x\n", mode);
    printf("Bits per word: %d\n", bits);
    printf("Max speed: %d Hz\n", speed);
}

int main(int argc, char *argv[])
{
    if (argc != 2) {
        printf("Usage: %s <string_to_send>\n", argv[0]);
        return 1;
    }

    char *tx_buffer = argv[1]; // 获取要发送的字符串作为命令行参数

    // 初始化SPI接口
    spi_init();

    // 设置要接收数据的缓冲区
    unsigned char rx_buffer[strlen(tx_buffer) + 1];

    // 执行SPI数据传输
    transfer(fd, tx_buffer, rx_buffer, strlen(tx_buffer));

    // 打印发送和接收的数据
    printf("Sent: %s\n", tx_buffer);
    printf("Received: %s\n", rx_buffer);

    // 关闭SPI设备
    close(fd);

    return 0;
}

接下来需要编译一下这个文件,用以下命令

sudo aarch64-linux-gnu-gcc spidev_test.c -o spidev_test

然后使用adb push上传到开发板上,进行测试并使用逻辑分析仪进行解析
在这里插入图片描述

  • 31
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值