IGKBoard(imx6ull)-SPI接口编程-回环测试

news2025/1/16 2:39:45

文章目录

    • 1- 使能imx6ull开发板SPI驱动
    • 2- 回环测试imx6ull开发板物理连接
    • 3- 编程SPI回环测试
    • 4- 代码重难点分析
      • (1)spi_device结构体
      • (2)spi_ioc_transfer结构体
      • (3)ioctl函数


对于SIP不了解的可以参考这篇文章:SPI协议介绍

1- 使能imx6ull开发板SPI驱动

想要使能40pin扩展口的SPI1的话,需要修改开发板上的DTOverlay配置文件,添加该管脚对SPI1的支持,具体修改具体方法为修改 eMMC 启动介质的 boot 分区下的 config.txt 文件,将dtoverlay_spi1的选项修改为yes,然后重启应用就可以了。

root@igkboard:~# vi /run/media/mmcblk1p1/config.txt
# Enable SPI overlay, SPI1 conflict with UART8(NB-IoT/4G module)
dtoverlay_spi1=yes

系统启动时将会自动加载 SPI 协议驱动。查看/dev下是否存在spi设备节点,已验证spi驱动是否加载。

root@igkboard:~# ls -l /dev/spidev0.0
crw------- 1 root root 153, 0 Mar  4 05:56 /dev/spidev0.0

2- 回环测试imx6ull开发板物理连接

我们可以看见开发板上的40pin扩展口上:
GPIO03_IO27 -----> ECSPI1_MOSI
GPIO03_IO28 -----> ECSPI1_MISO

在这里插入图片描述
回环测试,找到IGKBoard的SPI1的MISO和MOSI管脚,使用杜邦线或跳线帽短接即可,如下图所

在这里插入图片描述


3- 编程SPI回环测试

源码:

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

typedef struct spi_ctx_s
{
    int       fd;
    char      dev[64];
    uint8_t   bits;
    uint16_t  delay;
    uint32_t  mode;
    uint32_t  speed;
}spi_ctx_t;

static int spi_init(spi_ctx_t *spi_ctx);/*设备初始化函数*/
static int spi_transmit_receive(spi_ctx_t *spi_ctx, uint8_t const *tx, uint8_t const *rx,size_t len);

int main(int argc, char* argv[])
{
    char          *input_tx = "Hello.I am WangDengtao.";//默认发送的数据
    char          *spi_dev = "/dev/spidev0.0";//默认设备的位置
    uint32_t      spi_speed = 500000;//默认速率500k
    spi_ctx_t     spi_ctx;
    char          rx_buf[60];

    if(2 != argc)
    {
        printf("This is the procedure of spi loopback test.\n");
        printf("Please input %s /dev/spidev***.\n", argv[0]);
        return 0;
    }

    memset(&spi_ctx, 0, sizeof(spi_ctx));
    strncpy(spi_ctx.dev, spi_dev, sizeof(spi_ctx.dev));//将设备地址拷贝到结构体中,方便初始化调用

    spi_ctx.bits = 8;//数据长度
    spi_ctx.delay = 100;//两个spi_ioc_transfer之间的延时,微秒
    /*
#define SPI_MODE_0  (0|0)               //模式0
#define SPI_MODE_1  (0|SPI_CPHA)        //模式1
#define SPI_MODE_2  (SPI_CPOL|0)        //模式2
#define SPI_MODE_3  (SPI_CPOL|SPI_CPHA) //模式3
     */
    spi_ctx.mode = SPI_MODE_2;//设置spi模式
    spi_ctx.speed = spi_speed;///通讯速率

    if(spi_init(&spi_ctx) < 0)
    {
        printf("spi_init error\n");
        return -1;
    }
    printf("SPI %s [fd=%d] init successfully\n",spi_ctx.dev, spi_ctx.fd);

    if(spi_transmit_receive(&spi_ctx, input_tx, rx_buf, strlen(input_tx)) < 0)
    {
        printf("spi_transmit_receive error\n");
        return -2;
    }

    /*打印 tx_buf 和 rx_buf*/
    printf("tx_buf: | %s |\n", input_tx);
    printf("rx_buf: | %s |\n", rx_buf);

    return 0;
}

/*数据收发函数*/
static int spi_transmit_receive(spi_ctx_t *spi_ctx, uint8_t const *tx, uint8_t const *rx,size_t len)
{
    /*应用程序空间需要从spi设备传输数据时候每组数据元素就是 struct spi_ioc_transfer 结构体类型*/
    struct spi_ioc_transfer tr = {
        .tx_buf = (unsigned long)tx,
        .rx_buf = (unsigned long)rx,
        .len = len,
        .delay_usecs = spi_ctx->delay,
        .speed_hz = spi_ctx->speed,
        .bits_per_word = spi_ctx->bits,
    };

    if(ioctl(spi_ctx->fd, SPI_IOC_MESSAGE(1), &tr) < 0)
    {
        printf("SPI transmit and receive error: %s\n", strerror(errno));
        return -1;
    }

    return 0;
}

/*设备初始化函数*/
int spi_init(spi_ctx_t *spi_ctx)
{
    int ret;
    
    spi_ctx->fd = open(spi_ctx->dev, O_RDWR);
    if(spi_ctx->fd < 0)
    {
        printf("Open %s error:%s\n", spi_ctx -> dev, strerror(errno));
        return -1;
    }
    /*设置spi接收和发送的工作模式*/
    ret = ioctl(spi_ctx->fd, SPI_IOC_RD_MODE, &spi_ctx->mode);
    if(ret < 0)
    {
        printf("SPI set SPI_IOC_RD_MODE [0x%x] error:%s\n", spi_ctx->mode, strerror(errno));
        goto CleanUp;
    }
    ret = ioctl(spi_ctx->fd, SPI_IOC_WR_MODE, &spi_ctx->mode);
    if(ret < 0)
    {
        printf("SPI set SPI_IOC_WR_MODE [0x%x] error:%s\n", spi_ctx->mode, strerror(errno));
        goto CleanUp;
    }
    /*设置spi通信接收和发送的字长*/
    ret = ioctl(spi_ctx->fd, SPI_IOC_RD_BITS_PER_WORD, &spi_ctx->bits);
    if(ret < 0)
    {
        printf("SPI set SPI_IOC_RD_BITS_PER_WORD [%d] error:%s\n",spi_ctx->bits, strerror(errno));
        goto CleanUp;
    }
    ret = ioctl(spi_ctx->fd, SPI_IOC_WR_BITS_PER_WORD, &spi_ctx->bits);
    if(ret < 0)
    {
        printf("SPI set SPI_IOC_WR_BITS_PER_WORD [%d] error:%s\n",spi_ctx->bits, strerror(errno));
        goto CleanUp;
    }
    /*设置最高工作频率*/
    ret = ioctl(spi_ctx->fd, SPI_IOC_WR_MAX_SPEED_HZ, &spi_ctx->speed);
    if(ret == -1)
    {
        printf("SPI set SPI_IOC_WR_MAX_SPEED_HZ [%d] error:%s\n", spi_ctx->speed, strerror(errno));
        goto CleanUp;
    }
    ret = ioctl(spi_ctx->fd, SPI_IOC_RD_MAX_SPEED_HZ, &spi_ctx->speed);
    if(ret == -1)
    {
        printf("SPI set SPI_IOC_RD_MAX_SPEED_HZ [%d] error:%s\n", spi_ctx->speed, strerror(errno));
        goto CleanUp;
    }
    printf("spi mode: 0x%x\n", spi_ctx->mode);
    printf("bits per word: %d\n", spi_ctx->bits);
    printf("max speed: %d KHz\n", spi_ctx->speed /1000);

    return spi_ctx->fd;

CleanUp:
    close(spi_ctx->fd);
    return -1;
}

makefile:

CC=arm-linux-gnueabihf-gcc
APP_NAME=spi_test

all:clean
	@${CC} ${APP_NAME}.c -o ${APP_NAME}

clean:
	@rm -f ${APP_NAME}

tftp不了解的小伙伴可以参考这篇文章:wpa_supplicant无线网络配置imx6ull以及搭建tftp服务器
tftp服务器下载到开发板运行:

root@igkboard:~# tftp -gr spi_test 192.168.10.168
root@igkboard:~# chmod a+x spi_test
root@igkboard:~# ./spi_test /dev/spidev0.0 
spi mode: 0x4
bits per word: 8
max speed: 500 KHz
SPI /dev/spidev0.0 [fd=3] init successfully
tx_buf: | Hello.I am WangDengtao. |
rx_buf: | Hello.I am WangDengtao. |

4- 代码重难点分析

(1)spi_device结构体

虽然用户空间不需要直接用到spi_device结构体,但是这个结构体和用户空间的程序有密切的关系,理解它的成员有助于理解SPI设备节点的IOCTL命令,所以首先来介绍它。
在我们的代码中,我们就使用到了:

spi_ctx.mode = SPI_MODE_2;//设置spi模式
//设置读写的工作模式
ioctl(spi_ctx->fd, SPI_IOC_RD_MODE, &spi_ctx->mode);
ioctl(spi_ctx->fd, SPI_IOC_WR_MODE, &spi_ctx->mode);

SPI_MODE_2是设置spi模式为第二种模式,在开头推荐的第一篇文章中有讲到。

在内核中,每个spi_device代表一个物理的SPI设备:

struct spi_device {
         structdevice              dev;
         structspi_master         *master;
         u32                       max_speed_hz;        /* 通信时钟最大频率 */
         u8                        chip_select;         /* 片选号 */
         u8                        mode;                /*SPI设备的模式,下面的宏是它各bit的含义  */
#define       SPI_CPHA        0x01                      /* 采样的时钟相位                            */
#define       SPI_CPOL        0x02                      /* 时钟信号起始相位:高或者是低电平*/
#define       SPI_MODE_0     (0|0)                    
#define       SPI_MODE_1     (0|SPI_CPHA)
#define       SPI_MODE_2     (SPI_CPOL|0)
#define       SPI_MODE_3     (SPI_CPOL|SPI_CPHA)
#define       SPI_CS_HIGH     0x04                      /* 为1时片选的有效信号是高电平*/
#define       SPI_LSB_FIRST   0x08                      /* 发送时低比特在前  */
#define       SPI_3WIRE       0x10                      /* 输入输出信号使用同一根信号线 */
#define       SPI_LOOP        0x20                      /* 回环模式 */
         u8                        bits_per_word;       /* 每个通信字的字长(比特数) */
         int                       irq;                 /*使用到的中断 */
         void                     *controller_state;
         void                     *controller_data;
         char                      modalias[32];        /* 设备驱动的名字*/
};

(2)spi_ioc_transfer结构体

应用程序空间需要从spi设备传输数据时候,每组数据元素就是 struct spi_ioc_transfer 结构体类型,该结构体定义如下:

struct spi_ioc_transfer {
	__u64 tx_buf; //发送数据缓存
	__u64 rx_buf; //接收数据缓存
	
	__u32 len; //数据长度
	__u32 speed_hz; //通讯速率
	
	__u16 delay_usecs; //两个spi_ioc_transfer之间的延时,微秒
	__u8 bits_per_word; //数据长度
	__u8 cs_change; //取消选中片选
	__u8 tx_nbits; //单次数据宽度(多数据线模式)
	__u8 rx_nbits; //单次数据宽度(多数据线模式)
	__u8 word_delay_usecs;
	__u8 pad;
	/* If the contents of 'struct spi_ioc_transfer' ever change
	* incompatibly, then the ioctl number (currently 0) must change;
	* ioctls with constant size fields get a bit more in the way of
	* error checking than ones (like this) where that field varies.
	*
	* NOTE: struct layout is the same in 64bit and 32bit userspace.
	*/
};

(3)ioctl函数

在编写应用程序时还需要使用ioctl函数设置spi相关配置,其函数原型如下:

#include <sys/ioctl.h>
int ioctl(int fd, unsigned long request, ...);

其中对于SPI设备request的值常用的有以下几种:
在这里插入图片描述
当然,如果要使用上述的参数的话,需要头文件#include <linux/spi/spidev.h>


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/387593.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

GVRP-LNP-VCMP讲解

目录 GVRP讲解 动态创建Vlan并将端口加入Vlan GVRP消息类型 GVRP工作原理 LNP讲解 动态修改接口链路类型 VCMP讲解 动态创建Vlan 相关概念 Vlan同步 VCMP与GVRP的区别 GVRP讲解 动态创建Vlan并将端口加入Vlan GVRP&#xff08;GARR Vlan Registration Protocol&#xf…

28个案例问题分析---01---redis没有及时更新问题--Redis

redis没有及时更新问题一&#xff1a;背景介绍二&#xff1a;前期准备pom依赖连接Redis工具类连接mysql工具类三&#xff1a;过程使用redis缓存&#xff0c;缓存用户年龄业务对应流程图使用redis缓存用户年龄对应代码四&#xff1a;总结一&#xff1a;背景介绍 业务中使用redis…

【机器学习面试】百面机器学习笔记和问题总结+扩展面试题

第1章 特征工程 1、为什么需要对数值类型的特征做归一化&#xff1f; &#xff08;1&#xff09;消除量纲&#xff0c;将所有特征统一到一个大致相同的区间范围&#xff0c;使不同指标之间具由可比性&#xff1b; &#xff08;2&#xff09;可以加快梯度下降收敛的速度&#…

powershell-dns-txt远程加载

2022-10-30 参考原文&#xff1a; 远程下载的通用替代方案 &#xff5c; 红队攻防 https://mp.weixin.qq.com/s/9MAKZZfNB5YFT7jgln5lXQ实现过程 dns环境&#xff1a;kali bind9&#xff08;docker版&#xff09;&#xff0c;ip&#xff1a;192.168.161.128 靶机&#xff…

AD封装转Allego Cadence

AD封装转Allego CadenceAD封装转Allego Cadence软件版本转换步骤导出AD文件在PADS导入AD在cadence导入PADS在cadence导出library修改焊盘替换焊盘AD封装转Allego Cadence 有时候在网上下载的封装是AD格式的&#xff0c;但内容实在太多&#xff0c;为了快速便捷获得cadence格式…

梯度提升算法决策过程的逐步可视化

梯度提升算法是最常用的集成机器学习技术之一&#xff0c;该模型使用弱决策树序列来构建强学习器。这也是XGBoost和LightGBM模型的理论基础&#xff0c;所以在这篇文章中&#xff0c;我们将从头开始构建一个梯度增强模型并将其可视化。 梯度提升算法介绍 梯度提升算法&#x…

【VC 7/8】vCenter Server 基于文件的备份和还原Ⅰ——基于文件的备份和还原的注意事项和限制

目录1.1 协议1.2 还原后配置说明1.3 Storage DRS1.4 分布式电源管理1.5 分布式虚拟交换机1.6 内容库1.7 虚拟机生命周期操作1.8 vSphere High Availability1.9 基于存储策略的管理1.10 其它注意事项虚拟存储区域网络修补关联博文[图片来源]&#xff1a;https://www.vmignite.co…

ARM uboot 源码分析9 - uboot的硬件驱动部分

一、uboot 与 linux 驱动 1、uboot 本身是裸机程序 (1) 裸机本来是没有驱动的概念的&#xff08;狭义的驱动的概念就是&#xff0c;操作系统中用来具体操控硬件的那部分代码叫驱动&#xff09; (2) 裸机程序中是直接操控硬件的&#xff0c;操作系统中必须通过驱动来操控硬件…

Java 8 新特性之Stream流(二)关键

继续探索流API的高级功能之前&#xff0c;我们先从接口级别全面了解一下流API&#xff0c;这个对于我们来说是至关重要的。下面是一张流API关键知识点的UML图。 流API UML 流API定义的几个接口&#xff0c;都是在java.util.stream包中的.其中上图中的BaseStream接口是最基础的…

每日记录自己的Android项目(二)—Viewbinding,WebView,Navigation

今日想法今天是想把做一个跳转页面的时候调到H5页面去&#xff0c;但是这个页面我用app来承载&#xff0c;不要调到浏览器去。所以用到了下方三个东西。Viewbindingbuild.gradle配置首先在app模块的build.gradle里添加一下代码默认情况下&#xff0c;每一个布局xml文件都会生成…

【Linux学习】基础IO——理解缓冲区 | 理解文件系统

&#x1f431;作者&#xff1a;一只大喵咪1201 &#x1f431;专栏&#xff1a;《Linux学习》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交给时间&#xff01; 基础IO☕理解缓冲区&#x1f9c3;缓冲区的共识&#x1f9c3;缓冲区的位置&#x1f9c3;缓冲区的刷…

Spring Boot+Vue前后端分离项目练习03之网盘项目文件夹创建及文件查询接口开发

1.集成Swagger 3接口文档 在前后端分离的项目中&#xff0c;接口文档的存在十分重要。swagger 是一个自动生成接口文档的工具&#xff0c;在需求变更十分频繁的情况下&#xff0c;手写接口文档是效率十分低下&#xff0c;这时swagger自动生生文档的的作用就体现出来了&#xf…

【uni-app教程】UniAPP 常用组件和 常用 API 简介# 知心姐姐聊天案例

五、UniAPP 常用组件简介 uni-app 为开发者提供了一系列基础组件&#xff0c;类似 HTML 里的基础标签元素&#xff0c;但 uni-app 的组件与 HTML 不同&#xff0c;而是与小程序相同&#xff0c;更适合手机端使用。 虽然不推荐使用 HTML 标签&#xff0c;但实际上如果开发者写了…

华为机试题:HJ105 记负均正II(python)

文章目录&#xff08;1&#xff09;题目描述&#xff08;2&#xff09;Python3实现&#xff08;3&#xff09;知识点详解1、input()&#xff1a;获取控制台&#xff08;任意形式&#xff09;的输入。输出均为字符串类型。1.1、input() 与 list(input()) 的区别、及其相互转换方…

【Kubernetes】第十七篇 - ECS 服务停机和环境修复

一&#xff0c;前言 上一篇&#xff0c;介绍了 Secret 镜像的使用&#xff1b; 三台服务每天大概 15 块钱的支出&#xff0c;用一个月也是不少钱&#xff1b; 闲时可以停掉&#xff0c;这样每天只有 4 块钱支出&#xff0c;剩下一大笔&#xff1b; ECS 服务停机后公网 IP 会…

移除元素(每日一题)

目录 一、题目描述 二、题目分析 2.1 方法一 2.1.1 思路 2.1.2 代码 2.2 方法二 2.2.1 思路 2.2.2 代码 一、题目描述 题目链接&#xff1a;27. 移除元素 - 力扣&#xff08;LeetCode&#xff09; 给你一个数组 nums 和一个值 val&#xff0c;你需要 原地 移除所有数…

【Maven】P1 Maven 基础知识

Maven 基础知识Maven基础仓库坐标快速坐标生成网站国内镜像仓库前言 本节&#xff1a;Maven第一节内容&#xff0c;记录maven是什么&#xff0c;解决了什么问题&#xff0c;进而推出他的作用&#xff1b;然后介绍maven中两个重要概念&#xff0c;仓库与坐标。 下一节&#xff1…

TIA博途中使用SCL语言实现选择排序算法并封装成FC全局库

TIA博途中使用SCL语言实现选择排序算法并封装成FC全局库 选择排序算法包括升序和降序2种: 升序排列: 第一轮从数据源中找到最小值排在第一位,第二轮从剩下的数据中寻找最小值排在第二位,依次类推,直到所有数据完成遍历;降序排列: 第一轮从数据源中找到最大值排在第一位,…

centOS 编译strongswan

安装编译环境 yum groupinstall "Development Tools" 编译strongswan Download strongSwan: wget https://download.strongswan.org/strongswan-x.x.x.tar.bz2 Unpack the tarball and navigate into the directory: tar xjf strongswan-x.x.x.tar.bz2; cd strong…

Editor.md 的使用方法及图片处理

目录1. 资源下载2. 生成页面2.1 编辑和预览页面2.2 文本渲染页面3. 图片上传3.1 前端配置3.2 后端接口4. 图片粘贴1. 资源下载 官网下载 gitee 下载 2. 生成页面 2.1 编辑和预览页面 将资源&#xff08;精简后 Editor.md 资源1&#xff09;导入项目&#xff1a; 按照官方教…