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_SUN7Itristate "SUN7I SPI Controller"depends on ARCH_SUN7IhelpAllwinner Soc SPI controller,present on SUN7I chips.config SUN7I_SPI_NDMAbool "SUN7I SPI Normal DMA mode select"depends on SPI_SUN7IhelpThis selects SPI DMA mode with DMA transferY 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 0static 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

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

  1. STM32双机SPI全双工通信

    (基于STM32F407的SPI全双工通信时序不同步问题!!) 首先吐槽一波,调一个星期的SPI,始终没有很好的效果. 网上有很多SPI主从通信的例子,但是两片STM32单片机进行通信,基本很少,就算 ...

  2. SPI全双工通信解读和调试问题分析汇总

    写在前言: 致敬对这篇文档感兴趣的所有读者,关于对spi通信的解读,目前花费大概几个星期进行相关验证和调试,在这个过程中发生了很多奇怪的现象,一般来说spi控制形式多种多样,对于spi的全双工.半双工 ...

  3. USART串口全双工与SPI全双工通信的区别!

    目录 1.背景知识 2.SPI的全双工同通信 3.串口USART的全双工通信 背景知识 首先我们先来区分一下单工.半双工.全双工模式. 单工:数据传输只支持数据在一个方向上传输 半双工:允许数据传输在 ...

  4. SPI全双工通信--看懂这篇就够

    对于生活中大家普遍常用到的一些基本通信总线协议,也是成为大家关注的焦点,那么今天小易就同大家在知识海洋中进行一次比较深入的探讨,同时也希望小易的这篇文章能给大家带来一定的帮助.  SPI通信原理: S ...

  5. LinuX编译显示内核配置无效,配置编译内核(Linux kernel)

    虽然以前也编译过内核,但是关于内核配置选项特别是有关本机驱动这块还是不熟悉,因为没有通过确定有效的途径知道当前工作正常的内核中到底使用了什么驱动模块来控制硬件,最近看到一本书<Linux ker ...

  6. linux编译内核支持pam,linux编译内核make menuconfig报错解决办法

    linux编译内核时 输入make menuconfig命令 *** Unable to find the ncurses libraries or the *** required header f ...

  7. 一周一论文(翻译 总结)—— [SOSP 18] LITE Kernel RDMA Support for Datacenter Applications : 一个LITE 内核支持的RDMA通信库

    目录 Abstract 1. Introduction 2. BACKGROUND AND ISSUES OF RDMA 2.1 Background on RDMA 2.2 RDMA in Data ...

  8. 新增linux驱动并重新编译内核,【转】配置并编译内核[更新到linux-2.6.29.2]

    有关内核精简的内容,看3楼. 一.下载源代码和编译软件准备下载内核源代码:http://www.kernel.org/ 注意,点击2.6.29内核的F版,即完整版. 如果你懒得去网站点联接,运行下列命 ...

  9. 【嵌入式开发】 Linux Kernel 下载 配置 编译 安装 及 驱动简介

    作者 : 韩曙亮 转载请出名出处 : http://blog.csdn.net/shulianghan/article/details/38636827 一. Linux 内核简介 1. 内核功能简介 ...

  10. 编译内核,busybox,dropbear组装linux小系统

    应用程序使用以下软件 busybox提供命令环境 dropbear提供ssh服务实现远程管理. 查看本物理机的硬件,来确认编译内核时选择相应的驱动.硬件信息获取方法: cat /proc/cpuinf ...

最新文章

  1. c语言动态迁移mysql,flask-migrate动态迁移数据库
  2. 《数学之美》第8章 简单之美--布尔代数和搜索引擎
  3. 接口隔离原则最直白描述
  4. 吃万里路 |甜品店大盘点
  5. cdr文件过大导出pdf打不开_PDF文件过大怎样压缩?这才是压缩PDF最简单的方法
  6. 计算机网络利弊的作文英语作文,网络的弊端英语作文(精选6篇)
  7. C++基础教程之如何定义数字
  8. 微软要解决癌症问题?
  9. mysql order 中文版,MySQL Order By排序结果
  10. android开发深入浅出,Android开发深入浅出RxJava(一:基础篇)
  11. oracle查看密码过期策略及修改
  12. SQL Server 安全篇——安全元数据(2)——安全对象(Securable)元数据
  13. 手机usb计算机无法连接,手机usb连不上电脑怎么办实际解决
  14. Direct Rendering Manager (DRM)
  15. 从零开始搭建ROS移动机器人系列之(四)直流电机PWM调速
  16. disallow: /index.php?,那位高手知道robots文件的正确写法。我在网上看到两种说法。一种是 user-agent:* Disallow:/flims...
  17. tp路由器 拨号失败 服务器无响应,tp路由器wdr8500拨号不成功怎么办
  18. 商业调查——您可以下载 16 个免费问卷模板
  19. 777. 在LR字符串中交换相邻字符
  20. 奉劝学弟学妹,学完JavaScript就该学TypeScript了,让我们一起了解TypeScript和如何去搭建运行环境吧

热门文章

  1. linux系统下网络吞吐量/CPU占用率/流量控制的测试
  2. Hyper-V的使用技巧及管理方法
  3. php 忽略 deprecated,php升级后使用deprecated函数报错的解决方法
  4. Bloodsucker 【 ZOJ - 3551】
  5. 胎死腹中的天颖工作室-2004年初的痛楚
  6. STRATEGY(策略)模式
  7. 故事系列之二:佛法世界中看天赋与勤奋
  8. 函数的原函数,可积性和变上限积分之间的区别和联系
  9. 从Uniswap v3来看新的期权范式?
  10. PISCES: A Programmable, Protocol-Independent Software Switch(总结)