硬件接口说明:
主板上J2304插座对应CPU的SPI1,插座线序说明:
序号 | 说明 | 备注 |
---|---|---|
1 | VCC | 3.3V电源 |
2 | CLK | SPI时钟 |
3 | MOSI | |
4 | MISO | |
5 | CS | 片选 |
6 | GND | 电源地 |
1.1 SPI有4种模式,如下:
CPOL(时钟极性) 和 CPHA(时钟相位) 的不同组合,形成了SPI总线的不同模式.不同SPI从设备支持的模式.
模式 | CPOL | CPHA |
---|---|---|
模式一 | 0 | 0 |
模式二 | 0 | 1 |
模式三 | 1 | 0 |
模式四 | 1 | 1 |
1.2 时序图样例
以下以ubuntu-22.04.x-desktop-amd64 版本为例,
需要下载基本的编译工具,参考"Linux应用程序开发(调用硬件)"描述
以下是添加节点流程:
系统默认内核是不支持spi 设备的,
所以$ ls /dev/spi* 下找不到任何spi设备.
需要下载内核源码,配置内核编译开关:打开User mode SPI device driver support 选项
2.1 下载内核源码,开启User mode SPI device driver support 选项,并编译和安装新内核.
#更新源列表
jb@X1:~$ sudo apt-get update
#安装必须的插件 libssl 编译用相关
jb@X1:~$ sudo apt install -y libncurses-dev flex bison libssl-dev
#安装必须的插件libelf 编译用相关
jb@X1:~$ sudo apt-get -y install libelf-dev
#查看当前系统内核版本号
jb@X1:~$ uname -r
6.2.0-34-generic
#查看linux内核源码有哪些版本,选大版本和当前系统版本相同的,下面的 6.2.0是和本系统相同的
jb@X1:~$ sudo apt-cache search linux-source
linux-source - Linux kernel source with Ubuntu patches
linux-source-5.15.0 - Linux kernel source for version 5.15.0 with Ubuntu patches
linux-source-5.19.0 - Linux kernel source for version 5.19.0 with Ubuntu patches
linux-source-6.2.0 - Linux kernel source for version 6.2.0 with Ubuntu patches
#下载linux-source-6.2.0 内核源码
jb@X1:~$ sudo apt-get install linux-source-6.2.0
#进入下载源码目录
jb@X1:~$ cd /usr/src/
#解压内核源码到 当前用户目录
jb@X1:/usr/src$ tar -xvjf linux-source-6.2.0.tar.bz2 -C ~/
#进入源码目录
jb@X1:/usr/src$ cd ~/linux-source-6.2.0
#去打源码中老的配置
jb@X1:/usr/src$ sudo make oldconfig
#用当前系统的配置覆盖到源码中配置
jb@X1:~/linux-source-6.2.0$ cp /boot/config-$(uname -r) ./.config #拷贝系统原本内核的配置作为基配置
#进入图形配置界面,主要是启动User mode SPI device driver support 选项
jb@X1:~/linux-source-6.2.0$sudo make menuconfig
图形界面,开启spi device 支持:
Device Drivers-->
[*]SPI Support->
<*>User mode SPI device driver support
按空格是确定选中,选择成功是前面带<*>号
以上选好后,要保存一下.
参考后面的截图
#修改配置文件
jb@X1:~/linux-source-6.2.0$ sudo vim .config
通过 / 来查找以下字符串,并修改如下:大概位于 11357行 和11364行
删除等号后面双引号内的值
修改完成后如下:
CONFIG_SYSTEM_TRUSTED_KEYS=""
CONFIG_SYSTEM_REVOCATION_KEYS=""
#编译内核源码
jb@X1:~/linux-source-6.2.0$ sudo make -j4
#安装1
jb@X1:~/linux-source-6.2.0$ sudo make modules_install
#安装2
jb@X1:~/linux-source-6.2.0$ sudo make install
#更新启动参数
jb@X1:~/linux-source-6.2.0$ sudo update-grub
#重启系统
jb@X1:~/linux-source-6.2.0$ sudo reboot
$sudo make menuconfig 出现配置界面后,选择流程如下截图
选 Device Drivers--->
选 SPI support --->
开启 User mode SPI device driver support 按空格键选中,<>里面的M变成*号,并保存设置
确定保存
2.2 内核注入ACPI ASL CODE
spi-enable_upn-ehl01.zip 下载链接: http://dd.youyeetoo.cn:5000/sharing/IcRIU0zdD
注入流程如下
#新建一个文件夹
jb@X1:~$ sudo mkdir spi2
#进入文件夹
jb@X1:~$ cd spi2
#下载工具
jb@X1:~/spi2$ sudo curl -o spi-enable_upn-ehl01.zip http://d.youyeetoo.cn/X1/Linux-tools/linux-gpio-i2c-spi-nfc/spi/spi-enable_upn-ehl01.zip
#解压
jb@X1:~/spi2$ sudo unzip spi-enable_upn-ehl01.zip
#修改脚本权限
jb@X1:~/spi2$ sudo chmod 777 acpi-add
jb@X1:~/spi2$ sudo chmod 777 acpi-upgrades
jb@X1:~/spi2$ sudo chmod 777 install_hooks
#执行脚本,这过程是联网下载工具,若出现下载失败错误警告,重复执行几次,直到没有错误
jb@X1:~/spi2$ sudo ./install_hooks
#执行脚本:把asl code 注入内核
jb@X1:~/spi2$ sudo acpi-add spidev*
#重启系统
jb@X1:~/spi2$ sudo reboot
spidev1.1.asl 文件举例说明
/*
* This ASL can be used to declare a spidev device on SPI1 CS1
*/
DefinitionBlock ("", "SSDT", 5, "INTEL", "SPIDEV1", 0x00000001)
{
External (_SB.PC00.SPI1, DeviceObj)
Scope (\_SB.PC00.SPI1)
{
Device (TP1) //设备名
{
Name (_HID, "SPT0001") // _HID: Hardware ID
Name (_DDN, "SPI test device connected to CS1") // _DDN: DOS Device Name
Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings
{
SpiSerialBusV2 (
0x0001, //CS选择
PolarityLow, FourWireMode, 0x08,
ControllerInitiated,
0x000F4240, //速率
ClockPolarityLow,//CPOL
ClockPhaseFirst, //CPHA
"\\_SB.PC00.SPI1",
0x00, ResourceConsumer, , Exclusive,
)
})
}
}
}
3.3 完成以上操作后,验证一下是否在/dev下有节点
jb@X1:~$ ls /dev/spi*
/dev/spidev1.1
下载Linux-spi测试软件源码
linux-SPI-test-src-File
解压后,进入linux-spi文件夹,
源码目录结构说明:
文件 | 说明 |
---|---|
spi.h | SPI底层操作封装 |
spi.c | SPI底层操作封装 |
SpiCtrl.h | SPI应用接口头文件 |
SpiCtrl.cpp | SPI应用接口源文件 |
test_spi.cpp | 测试代码main |
Makefile | make编译脚本文件 |
需要下载基本的编译工具,参考"Linux应用程序开发(调用硬件)"描述
编译和运行测试程序如下如下:
#编译
jb@X1:~/linx-spi$ make
#执行
jb@X1:~/linx-spi$ sudo ./test_spi
若上面流程没有错误,执行程序结果如下;
$ sudo ./test_spi
打开spi成功,同步读写操作
SPI_FullDuplex成功,读取内容:FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
bye
接口文件SpiCtrl.h说明
#ifndef _SPI_CTRL_H
#define _SPI_CTRL_H
#include <stdint.h>
#include "spi.h"
class SpiCtrl
{
private:
spi_t *spi;
public:
SpiCtrl();
~SpiCtrl();
public:
/**
* @brief : 打开连接SPI总线
* @param {char} *path: spi总线路径 :/dev/spix
* @param {unsigned int} mode:模式:0,1,2,3
* @param {uint32_t} max_speed:速率
* @return {*}返回0成功,其他失败
**/
int32_t Open(const char *path, unsigned int mode,uint32_t max_speed);
/**
* @brief : 打开连接SPI总线 高级方法
* @param {char} *path: spi总线路径 :/dev/spix
* @param {unsigned int} mode:模式:0,1,2,3
* @param {uint32_t} max_speed:速率
* @param {spi_bit_order_t} bit_order:大端小端MSB_FIRST,LSB_FIRST
* @param {uint8_t} bits_per_word:设置SPI通信的字长
* @param {uint8_t} extra_flags:扩展参数
* @return {*}返回0成功,其他失败
**/
int32_t open_advanced(const char *path, unsigned int mode,uint32_t max_speed, spi_bit_order_t bit_order,uint8_t bits_per_word, uint8_t extra_flags);
/**
* @brief : 释放SPI总线
* @return {*}
**/
void Release();
/**
* @brief : SPI总线是否打开
* @return {*}
**/
bool isOpen();
/**
* @brief : SPI 先写后读数据
* @param {uint8_t} *lpWriteBuf:待写数据内存
* @param {int32_t} WriteBuf_len:数据长度
* @param {uint8_t} *lpReadBuf:待读数据内存
* @param {int32_t} ReadBuf_len:数据长度
* @return {*}返回0成功,其他失败
**/
int32_t SPI_WriteRead( uint8_t *lpWriteBuf, int32_t WriteBuf_len, uint8_t *lpReadBuf, int32_t ReadBuf_len);
/**
* @brief : SPI 仅写
* @param {uint8_t} *lpWriteBuffer:待写数据内存
* @param {int32_t} WriteLength:数据长度
* @return {*}返回0成功,其他失败
**/
int32_t SPI_Write( uint8_t *lpWriteBuffer, int32_t WriteLength);
/**
* @brief : SPI 同步写读
* @param {uint8_t} *lpWriteBuf:待写数据内存
* @param {uint8_t} *lpReadBuf:待同步读数据内存
* @param {int32_t} len:数据长度
* @return {*}返回0成功,其他失败
**/
int32_t SPI_FullDuplex( uint8_t *lpWriteBuf, uint8_t *lpReadBuf, int32_t len);
};
#endif
操作流程:
1)选择模式,速率,然后"连接SPI设备"
2)操作:
"SPI仅写":只写不读,需要根据从设备的通讯时序选择该操作.
"SPI先写后读":先写数据给从设备,后续读数据,需要根据从设备的通讯时序选择该操作.
"SPI同步写读":边写数据给从设备同时从设备读数据,需要根据从设备的通讯时序选择该操作.
测试程序qt界面样例源码和如何编译使用,请参考如下页面:
http://wiki.youyeetoo.cn/zh/x1/linux/qt-build