【Cubieboard2】配置编译内核支持SPI全双工通信驱动

【Cubieboard2】配置编译内核支持SPI全双工通信驱动1,cubieboard2A20系列,无论是官方还是社区的系统,默认都是不支持SPI总线驱动的。需要重新编译配置内核,修改文件才能支持SPI全双工通信。本文以Cuieboard2Debain为例,进行讲解;2,重新编译配置内核(1)先去官网下载对应版本的linux内核源码,地址:https://github.com/linux-sunxi/linux-sunxi我下载的是sun-xi

大家好,又见面了,我是你们的朋友全栈君。

1,cubieboard2 A20系列,无论是官方还是社区的系统,默认都是不支持SPI总线驱动的。需要重新编译配置内核,修改文件才能支持SPI全双工通信。本文以Cuieboard2 Debain为例,进行讲解;

2,重新编译配置内核

(1)先去官网下载对应版本的linux内核源码,地址:https://github.com/linux-sunxi/linux-sunxi 我下载的是sun-xi3.4

或者直接git 

git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git

(2)找一台安装了Ubuntu系统的机器,将源代码解压并进入解压根目录;(也可以直接在Cubieboard2板子上进行编译,但是效率慢,依赖库问题比较多,不建议这样做;)

1、需要预先安装arm-linux-gnueabihf 交叉编译工具,可以先使用 apt-get cache search arm-linux ; 然后选择对应的文件 apt-get install XX;

2、之后先将sun-xi 7i 的默认编译配置复制到 .config中: 输入

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- sun7i_defconfig

ARCH=arm 非常关键,程序会进入到/arch/arm目录中去寻找 sun7i_defconfig 配置文件;

3、在linux-sunxi/drivers/spi/ 下创建文件spi-sun7i.c   文件内容见本文末尾;

4、修改 linux-sunxi/drivers/spi/Makefile 文件,在末尾加上下句:

obj-$(CONFIG_SPI_SUN7I)         += spi-sun7i.o

5、修改linux-sunxi/drivers/spi/Kconfig 文件,加上下面内容:

config SPI_SUN7I
   tristate "SUN7I SPI Controller"
   depends on ARCH_SUN7I
   help
      Allwinner Soc SPI controller,present on SUN7I chips.

config SUN7I_SPI_NDMA
        bool "SUN7I SPI Normal DMA mode select"
        depends on SPI_SUN7I
        help
          This selects SPI DMA mode with DMA transfer
          Y select NDMA mode and N select DDMA mode

6、在根目录下,输入 vim .config

加入或修改如下内容:

CONFIG_SPI_SUN7I=y
CONFIG_SUN7I_SPI_NDMA=y

7、编译内核:

make -j 4 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- uImage modules
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- INSTALL_MOD_PATH=output modules_install

8、如果编译成功,那么在 /arch/arm/boot/ 下面会有uImage文件生成,这就是新的内核了。 第二句会生成新的module文件,在output文件价下。

9、切换到Cubieboard2 Debian系统下, 首先 mkdir /media/nanda 新建挂载点; mount /dev/nanda /media/nanda 挂载系统;

将新编译的uImage内核替换 /media/nanda/ 下的uImage文件; 将新生成的 outpiut/lib/modules/ 下的文件拷贝覆盖到 debian的/lib/modules 下,替换原来的文件;

(3)修改文件

进入/media/nanda/ 目录, cp script.bin script.bin.bak 先备份要修改的文件;

bin2fex script.bin script.fex 将bin文件转换为fex文件;

vim script.fex 修改文件如下内容(没有的请自行添加):

[spi0_para]
spi_used = 1
spi_cs_bitmap = 1
spi_cs0 = port:PI10<2><default><default><default>
spi_cs1 = port:PI14<2><default><default><default>
spi_sclk = port:PI11<2><default><default><default>
spi_mosi = port:PI12<2><default><default><default>
spi_miso = port:PI13<2><default><default><default>

[spi_devices]
spi_dev_num = 1

[spi_board0]
modalias = "spidev"
max_speed_hz = 100000
bus_num = 0
chip_select = 0
mode = 0
full_duplex = 1
manual_cs = 0

fex2bin script.fex script.bin 将fex文件转换为bin文件;并替换/media/nanda/script.bin 文件;

要想实现spi全双工通信,下面一步至关重要,这个文件必须修改:

修改Cubieboard2 Debian下的 /usr/include/linux/spi/spidev.h 为如下内容(其实只是增加了一句代码,但是必须改):

struct spi_ioc_transfer {
 __u64 tx_buf;
 __u64 rx_buf;

 __u32 len;
 __u32 speed_hz;

 __u16 interbyte_usecs;
 __u16 delay_usecs;
 __u8 bits_per_word;
 __u8 cs_change;
 __u32 pad;
}

保存文件重启系统;

3. 验证是否SPI是否配置成功

(1)重启后,在/dev 目录下看是否生成了 spidev0.0 文件,如果有,那么已经成功了一多半了;

(2)将Cubieboard2上的spi MOSI MISO进行短接(形成回环)自己发自己收,然后编写测试代码如下:

/*
* 说明:SPI通讯实现
* 方式一: 同时发送与接收实现函数: SPI_Transfer()
* 方式二:发送与接收分开来实现
* SPI_Write() 只发送
* SPI_Read() 只接收
* 两种方式不同之处:方式一,在发的过程中也在接收,第二种方式,收与发单独进行
* Created on: 2013-5-28
* Author: lzy
*/

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


#include "Debug.h"
#define SPI_DEBUG 0


static const char *device = "/dev/spidev0.0";
static uint8_t mode = 0; /* SPI通信使用全双工,设置CPOL=0,CPHA=0。 */
static uint8_t bits = 8; /* 8bits读写,MSB first。*/
static uint32_t speed = 100 * 1000;/* 设置100K传输速度 */
static uint16_t delay = 0;
static int g_SPI_Fd = 0;


static void pabort(const char *s)
{
perror(s);
abort();
}


/**
* 功 能:同步数据传输
* 入口参数 :
* TxBuf -> 发送数据首地址
* len -> 交换数据的长度
* 出口参数:
* RxBuf -> 接收数据缓冲区
* 返回值:0 成功
*/
int SPI_Transfer(const uint8_t *TxBuf, uint8_t *RxBuf, int len)
{
int ret;
int fd = g_SPI_Fd;


struct spi_ioc_transfer tr ={
.tx_buf = (unsigned long) TxBuf,
.rx_buf = (unsigned long) RxBuf,
.len =len,
.delay_usecs = delay,
};


ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
if (ret < 1)
pr_err("can't send spi message");
else
{
#if SPI_DEBUG
int i;
pr_debug("nsend spi message Succeed");
pr_debug("nSPI Send [Len:%d]: ", len);
for (i = 0; i < len; i++)
{
if (i % 8 == 0)
printf("nt");
printf("0x%02X ", TxBuf[i]);
}
printf("n");


pr_debug("SPI Receive [len:%d]:", len);
for (i = 0; i < len; i++)
{
if (i % 8 == 0)
printf("nt");
printf("0x%02X ", RxBuf[i]);
}
printf("n");
#endif
}
return ret;
}


/**
* 功 能:发送数据
* 入口参数 :
* TxBuf -> 发送数据首地址
*len -> 发送与长度
*返回值:0 成功
*/
int SPI_Write(uint8_t *TxBuf, int len)
{
int ret;
int fd = g_SPI_Fd;


ret = write(fd, TxBuf, len);
if (ret < 0)
pr_err("SPI Write errorn");
else
{
#if SPI_DEBUG
int i;
pr_debug("nSPI Write [Len:%d]: ", len);
for (i = 0; i < len; i++)
{
if (i % 8 == 0)
printf("nt");
printf("0x%02X ", TxBuf[i]);
}
printf("n");


#endif
}


return ret;
}


/**
* 功 能:接收数据
* 出口参数:
* RxBuf -> 接收数据缓冲区
* rtn -> 接收到的长度
* 返回值:>=0 成功
*/
int SPI_Read(uint8_t *RxBuf, int len)
{
int ret;
int fd = g_SPI_Fd;
ret = read(fd, RxBuf, len);
if (ret < 0)
pr_err("SPI Read errorn");
else
{
#if SPI_DEBUG
int i;
pr_debug("SPI Read [len:%d]:", len);
for (i = 0; i < len; i++)
{
if (i % 8 == 0)
printf("nt");
printf("0x%02X ", RxBuf[i]);
}
printf("n");
#endif
}


return ret;
}


/**
* 功 能:打开设备 并初始化设备
* 入口参数 :
* 出口参数:
* 返回值:0 表示已打开 0XF1 表示SPI已打开 其它出错
*/
int SPI_Open(void)
{
int fd;
int ret = 0;


if (g_SPI_Fd != 0) /* 设备已打开 */
return 0xF1;


fd = open(device, O_RDWR);
if (fd < 0)
pabort("can't open device");
else
pr_debug("SPI - Open Succeed. Start Init SPI...n");


g_SPI_Fd = fd;
/*
* spi mode
*/
ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
if (ret == -1)
pabort("can't set spi mode");


ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
if (ret == -1)
pabort("can't get spi mode");


/*
* bits per word
*/
ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
if (ret == -1)
pabort("can't set bits per word");


ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
if (ret == -1)
pabort("can't get bits per word");


/*
* max speed hz
*/
ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
if (ret == -1)
pabort("can't set max speed hz");


ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
if (ret == -1)
pabort("can't get max speed hz");


pr_debug("spi mode: %dn", mode);
pr_debug("bits per word: %dn", bits);
pr_debug("max speed: %d KHz (%d MHz)n", speed / 1000, speed / 1000 / 1000);


return ret;
}


/**
* 功 能:关闭SPI模块
*/
int SPI_Close(void)
{
int fd = g_SPI_Fd;


if (fd == 0) /* SPI是否已经打开*/
return 0;
close(fd);
g_SPI_Fd = 0;


return 0;
}


/**
* 功 能:自发自收测试程序
* 接收到的数据与发送的数据如果不一样 ,则失败
* 说明:
* 在硬件上需要把输入与输出引脚短跑
*/
int SPI_LookBackTest(void)
{
int ret, i;
const int BufSize = 16;
uint8_t tx[BufSize], rx[BufSize];


bzero(rx, sizeof(rx));
for (i = 0; i < BufSize; i++)
tx[i] = i;


pr_debug("nSPI - LookBack Mode Test...n");
ret = SPI_Transfer(tx, rx, BufSize);
if (ret > 1)
{
ret = memcmp(tx, rx, BufSize);
if (ret != 0)
{
pr_err("LookBack Mode Test errorn");
//pabort("error");
}
else
pr_debug("SPI - LookBack Mode OKn");
}

return ret;
}

上面两项都测试通过了,那么你的SPI内核态驱动已经完成了。剩下的就是根据需求编写用户态驱动了;(很简单,就是跟操作文件一样)

4、注意事项:

(1)如果你的Cubieboard2 Debian是从NAND启动的,那么在重新编译内核的时候需要增加NAND的驱动支持,具体方法可以  make ARCH=arm menuconfig 或者直接修改.config 文件将NAND相关部分改为y   默认是不支持NAND驱动的;

(2)使用逻辑分析仪进行分析是非常可靠的。软件可能有问题,但是逻辑分析仪是直接测量的电平,很有说服力;注意spi的频率设置,一般100Khz-500khz就够了,太大了板子顶不住,而且逻辑分析仪的采样频率要比spi的频率高才能正确采样;

(3)关于Cubieboard2的针脚 只支持spi0  这个设备,具体定义见: 

http://linux-sunxi.org/A20/PIO 

http://docs.cubieboard.org/products/a10_cubieboard/expansion_ports

(4)关于spi-sun7i.c 文件下载连接: 

http://download.csdn.net/detail/u010352603/9548040

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/163045.html原文链接:https://javaforall.net

(0)
上一篇 2022年7月22日 下午4:36
下一篇 2022年7月22日 下午4:36


相关推荐

  • pycharm中最常用的10个快捷键总结_PyCharm快捷键

    pycharm中最常用的10个快捷键总结_PyCharm快捷键代码编辑快捷键序号快捷键作用1CTRL+ALT+SPACE快速导入任意类2CTRL+SHIFT+ENTER代码补全3SHIFT+F1查看外部文档4CTRL+Q快速查找文档5CTRL+P参数信息(在方法中调用的参数)6CTRL+MOUSEOVERCODE基本信息7CTRL+F1显示错误或警告的描述8CTRL+I…

    2022年8月25日
    8
  • 没有风投的创业法则

    没有风投的创业法则

    2021年7月29日
    58
  • visio2019画思维导图

    visio2019画思维导图打开 vsio2019 新建模板 灵感触发图 选择模板一 2019 4 2215 02 32

    2026年3月19日
    2
  • yum安装jenkins

    yum安装jenkins部署 java 环境 jdk 下载 https www oracle com java technologies javase jdk16 downloads html 安装 rpm ivhjdk 16 linux x64 bin rpm 环境变量配置 vim etc profile 添加环境变量 exportJAVA HOME usr java jdk 16exportPATH PATH JAVA HOME binexportCLA JAVA HOME

    2026年3月17日
    2
  • Windows下cmd进入MySql的命令界面

    Windows下cmd进入MySql的命令界面####win+R快捷键打开运行,输入cmd,进入cmd若未将MySql加入环境变量,切换到mysql的安装目录下的bin目录;若已加入环境变量,则不必切换目录。输入主机名、数据库名、密码mysql-hlocalhost-uroot-p输入数据库密码

    2022年6月4日
    30
  • 向量到一个平面的投影向量

    向量到一个平面的投影向量向量到一个平面的投影向量求一个向量投影到一个平面上的投影向量 如下图已知项 向量 sq 平面法向量 n 设点 o 为点 q 到平面的垂点则向量 oq 垂直于平面则向量 so 即为 sq 在平面上的投影 so sq qoso sq n 1 qo so sq n 1 sq n 在上面的推理中对于 qo 的一步步转换是这样的因为 qo 平行于 n 但是方向相反 且 n 是单位向量所以 qo n 1 qo 因为 q

    2026年3月18日
    1

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号