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

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

文章目录

    • 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;//默认速率500kspi_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_testall: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>


相关文章:

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

文章目录1- 使能imx6ull开发板SPI驱动2- 回环测试imx6ull开发板物理连接3- 编程SPI回环测试4- 代码重难点分析&#xff08;1&#xff09;spi_device结构体&#xff08;2&#xff09;spi_ioc_transfer结构体&#xff08;3&#xff09;ioctl函数对于SIP不了解的可以参考这篇文章&…...

Python基础学习10——类

基本概念 面向对象编程是最有效的软件编写方法之一。理解面向对象编程可以让你像程序员那样从一个更加宏观的角度去理解代码&#xff0c;并大大提高程序员之间的合作效率。面向对象编程的两个核心概念是对象和类 **对象&#xff1a;**对象是能帮助我们解决问题的具体东西。比如…...

项目实战典型案例14——代码结构混乱 逻辑边界不清晰 页面美观设计不足

代码结构混乱 逻辑边界不清晰 页面美观设计不足一&#xff1a;背景介绍问题1 代码可读性差&#xff0c;代码结构混乱问题2 逻辑边界不清晰&#xff0c;封装意识缺乏示例3.展示效果上的美观设计二&#xff1a;思路&方案问题一&#xff0c;代码可读性差&#xff0c;代码结构混…...

SpringBoot 读取自定义Properties参数

目录 1. 概述 2. 实现方式 2.1 Value方式 2.2 PropertySource与ConfigurationProperties相结合 3. 结束 1. 概述 最近想尝试写一个定时任务管理&#xff0c;相关参数不想在Spring的配置文件Application.yml或者Application.properties获取。想自己新建一个properties文件。顺…...

机器学习100天(三十七):037 朴素贝叶斯-挑个好西瓜!

《机器学习100天》完整目录:目录 机器学习100天,今天讲的是:朴素贝叶斯-挑个好西瓜! 红色石头已经了解了贝叶斯定理和朴素贝叶斯法,接下来已经可以很自信地去买瓜了。买瓜之前,还有一件事情要做,就是搜集样本数据。红色石头通过网上资料和查阅,获得了一组包含 10 组样…...

c#遍历窗口,根据标题获取handle并显示窗口

using System.Runtime.InteropServices;using System.Text;//1&#xff0c;定义//[DllImport("User32.dll", EntryPoint "FindWindow")]//public extern static IntPtr FindWindow(string lpClassName, string lpWindowName);[DllImport("user32.dll…...

MyBatis高频面试专题

一、介绍下MyBatis中的工作原理 1。介绍MyBatis的基本情况&#xff1a;ORM 2。原理&#xff1a; MyBatis框架的初始化操作处理SQL请求的流程 1.系统启动的时候会加载解析全局配置文件和对应映射文件。加载解析的相关信息存储在 Configuration 对象 Testpublic void test1(…...

曹云金郭德纲关系迎曙光,新剧《猎黑行动》被德云社弟子齐点赞

话说天下大势&#xff0c;分久必合&#xff0c;合久必分。这句话经过了历史的证明&#xff0c;如今依然感觉非常实用。 就拿郭德纲和曹云金来说&#xff0c;曾经后者是前者的得门生&#xff0c;两个人不但情同父子&#xff0c;曹云金还是郭德纲默认接班人。然而随着时间的流逝&…...

如何在 OpenEuler 系统中安装 Docker

Docker 是一种流行的开源容器化平台&#xff0c;它能够将应用程序与其依赖项打包成可移植的容器&#xff0c;从而简化了应用程序的部署和管理。本文将介绍在 OpenEuler 系统中安装 Docker 并使用 Docker 容器控制 5G 模块的具体步骤。 安装 Docker 安装 Docker 的具体步骤如下…...

MySQL日志管理

日志管理在数据库保存数据时&#xff0c;有时候不可避免会出现数据丢失或者被破坏&#xff0c;这种时候&#xff0c;我们必须保证数据的安全性和完整性&#xff0c;就需要使用日志来查看或者恢复数据了数据库中数据丢失或被破坏可能原因&#xff1a;误删除数据库数据库工作时&a…...

进 制

进制进制一、进制概念二、进制的转换三、二进制的运算3.1 与运算3.2 或运算3.3 非运算3.4 异或运算3.5 位运算&#xff08;位移&#xff09;四、原码、反码、补码4.1 原码4.2 反码4.3 补码五、浮点数十进制转换成二进制进制 一、进制概念 十进制是指逢十进一。 计算机中二进制…...

pycharm关联github、新建以及更新仓

此处已经默认你安装了git以及pycharm,这篇文章将会教给大家如何利用pycharm管理自己的github. 目录 pycharm关联github设置 Github创建新的仓 仓库的更新 pycharm:2022。不同版本界面略有不同。 pycharm关联github设置 设置PyCharm&#xff0c;打开File --> Settings -…...

java基础知识之小碎片(自问自答版本)---嘻嘻,春招加油呀~

1.public/private/protected/default的区别&#xff1f; public:对所有类可见 private 只有类本身可以访问&#xff0c;其他类想访问可以通过该类的成员方法访问如getter/setter protected:对同一包内的类和所有子类可见 default:在同一包内可见&#xff0c;不加修饰符 2.jav…...

蚁群算法c++

//轮盘赌选择下一步行进城市 int citySelect(int k, int f) { int c 0;//记录蚂蚁可行进的城市个数 //1、计算可行进的各城市 选择概率 for (int m 0; m < cityNum; m) { //若城市&#xff08;i,j&#xff09;之间有路且j不在蚂蚁k的禁忌表中&#xf…...

北大青鸟天府校区IT学习大揭秘

口罩已放开&#xff0c;一切都要重新出发。 开年才一个多月&#xff0c;已经有很多小伙伴想培训转行IT行业或者已经在咨询、报名培训IT技术。作为老牌培训机构&#xff0c;也有很多小伙伴相信我们&#xff0c;选择了我们。很感谢大家的信任&#xff0c;作为老牌培训机构&#…...

04 Linux errno.h错误码中文注释

Linux错误码中文注释 作者将狼才鲸创建日期2023-03-04/******************************************************************************* \brief 错误码* \note 基于linux_6.1-rc4\include\uapi\asm-generic\errno-base.h* linux_6.1-rc4\tools\arch\alpha\include\uapi…...

MySQL表的约束

文章目录表的约束空属性默认值列描述zerofill主键自增长唯一键外键表的约束 真正约束字段的是数据类型&#xff0c;但是数据类型约束很单一&#xff0c;需要有一些额外的约束&#xff0c;更好的保证数据的合法性&#xff0c;从业务逻辑角度保证数据的正确性。比如说我们的居民…...

Go语言的条件控制语句及循环语句的学习笔记

一、Go的条件控制语句 Go 语言提供了以下几种条件判断语句&#xff1a; 语句描述if 语句if 语句 由一个布尔表达式后紧跟一个或多个语句组成。if…else 语句if 语句 后可以使用可选的 else 语句, else 语句中的表达式在布尔表达式为 false 时执行。if 嵌套语句你可以在 if 或…...

D. Linguistics(思维 + 贪心)

Problem - D - Codeforces Alina发现了一种奇怪的语言&#xff0c;它只有4个单词:a, B, AB, BA。事实也证明&#xff0c;在这种语言中没有空格:一个句子是通过将单词连接成一个字符串来写的。Alina发现了一个这样的句子&#xff0c;她很好奇:有没有可能它恰好由a个单词a, b个单…...

maxWell数据迁移

目录 1.开启mysql的binlog 1.1: Statement-based 1.2: Row-based 1.3: mixed 2. 重启mysql服务 3. 创建Maxwell所需数据库和用户 4. 配置Maxwell 5. Maxwell启停(实时同步) 6. 历史数据全量同步 这里使用maxWell对mysql数据迁移到kafka中 官网下载地址点击下载 注&#x…...

混合图像python旗舰版

仔细看这个图像。然后后退几米再看。你看到了什么&#xff1f;混合图像是指将一张图片的低频与另一张图片的高频相结合的图片。根据观看距离的不同&#xff0c;所得到的图像有两种解释。在上面的图片中&#xff0c;你可以看到阿尔伯特爱因斯坦&#xff0c;一旦你离开屏幕或缩小…...

开发手册——一、编程规约_5.集合处理

这篇文章主要梳理了在java的实际开发过程中的编程规范问题。本篇文章主要借鉴于《阿里巴巴java开发手册终极版》 下面我们一起来看一下吧。 1. 【强制】关于 hashCode 和 equals 的处理&#xff0c;遵循如下规则&#xff1a; 只要重写 equals&#xff0c;就必须重写 hashCod…...

【elastic】elastic高可用集群部署

文章目录前言一、资源分享1、包含源码包、配置文件二、部署过程三、报错锦集四、es的部分相关命令前言 本博客内容仅为记录博主思路&#xff0c;仅供参考&#xff0c;一切以自己实践结果为准。 一、资源分享 1、包含源码包、配置文件 链接&#xff1a;https://pan.baidu.com…...

初识Liunx下的进程状态和环境变量以及进程优先级

文章目录前言1.进程状态1.阻塞与挂起2.Linux下的进程状态1.概念知识2.R状态2.休眠状态(S/D&#xff09;3.T状态4.Z状态(僵尸进程)和X状态5.孤儿进程3.环境变量1.概念2.获取环境变量1.环境变量表2.函数获取环境变量3.关于环境变量的理解和main函数中的两个参数1.环境变量的理解2…...

JavaEE——何为线程及创建线程

文章目录一、认识线程1. 线程的概念2. 出现多线程的原因3. 进程与线程4. 对多线程的详细解释二、初次实现多线程代码1. 初步了解2. 使用 Java 中的工具查看当前的所有线程3. Java 中创建线程的多种方式一、认识线程 1. 线程的概念 所谓线程&#xff0c;就是指在一个 ‘执行流…...

linux配置核查MySQL 配置规范 (Linux)_S3A3G3

linux的配置核查问题&#xff1a; 解决&#xff1a; 1.检查是否禁止mysql对本地文件存取 方法一&#xff1a;在my.cnf的mysql字段下加local-infile0 方法二&#xff1a;启动mysql时加参数local-infile0 /etc/init.d/mysql start --local-infile0 假如需要获取本地文件&#xf…...

Protobuf简介

Protobuf简介 1. Protocol Buffers1.1. 什么是Protocol Buffers?1.2. 选择你最喜欢的语言1.3. 如何开始2. Protocol Buffer Basics: C++2.1. 问题领域2.2. 在哪里找到示例代码2.3. 定义协议格式(Defining Your Protocol Format)1. Protocol Buffers Protocol Buffers(协议缓冲…...

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

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

Vue2的生命周期(详解)

Vue的生命周期一、生命周期的概念二、钩子函数三、Vue2的生命周期3.1 初始化阶段3.2 挂载阶段3.3 更新阶段3.4 销毁阶段一、生命周期的概念 Vue实例的生命周期: 从创建到销毁的整个过程 二、钩子函数 Vue框架内置函数,随着组件的生命周期阶段,自动执行 作用:特定的时间点,执行特…...

Potions (Hard Version) and (Easy Version)(背包DP + 反悔贪心)

[TOC](Potions (Hard Version) and (Easy Version)) 一、Potions(Easy Version) 1、问题 2、分析&#xff08;背包DP 贪心&#xff09; 简而言之就是我们需要从左到右开始选数字&#xff0c;选的过程中我们需要保证我们选的数字的和始终是大于等于0的&#xff0c;在满足这个…...