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

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


  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
雅可比迭代法求解线性方程组的实验报告 一、实验题目 分别利用雅可比迭代法和高斯-塞德尔迭代法求解以下线性方程组: 使得误差不超过 0.00001。 二、实验引言 1.实验目的 掌握用迭代法求解线性方程组的基本思想和步骤,熟悉计算机fortran语言; 了解雅可比迭代法在求解方程组过程中的优缺点。 2.实验意义 雅克比迭代法就是众多迭代法中比较早且较简单的一种,求解方便实用。 三、算法设计 1.雅可比迭代法原理: 设有线性方程组Ax=b 满足, 将方程组变形为: x=Bx+f, 则雅可比(Jacobi)迭代法是指,即 由初始解逐步迭代即可得到方程组的解。 算法步骤如下: 步骤1.给定初始值,精度e,最大容许迭代次数M,令k=1。 步骤2.对i=1,2,…,n依次计算 步骤3.求出,若,则输出结果,停止计算。否则执行步骤4. 步骤4.若转步骤2继续迭代。若表明迭代失败,停止计算。 2.算法流程图 四、程序设计 program jacobi implicit none integer::i,j integer::k save k real,parameter::e=0.001 integer,parameter::n=3 real::x(n),y(n),b(n) data b/7.2,8.3,4.2/ real::D real::a(n,n) open (unit=10,file='1.txt') data a/10,-1,-1,-1,10,-1,-2,-2,5/ write(10,*)"**********矩阵A的形式为**********" write(10,"(1x,3f6.2,/)")a forall(i=1:n) x(i)=0 end forall k=0 100 D=0 do i=1,n y(i)=b(i) do j=1,n if(i/=j) y(i)=y(i)-a(i,j)*x(j) end do y(i)=y(i)/a(i,i) end do do j=1,n D=abs(x(j)-y(j)) end do forall(i=1:n) x(i)=y(i) end forall if(D>=e) then k=k+1 write(10,*)"迭代次数为:",k goto 100 else goto 200 end if 200 write(10,*)"****************************************" write(10,*)"用jacobi方法解得的结果X[t]为:" write(10,"(1x,3f6.2,/)")x(:) stop end program 五、结果及讨论 1.实验结果 **********矩阵A的形式为********** 10.00 -1.00 -1.00 -1.00 10.00 -1.00 -2.00 -2.00 5.00 迭代次数为: 1 迭代次数为: 2 迭代次数为: 3 迭代次数为: 4 迭代次数为: 5 迭代次数为: 6 迭代次数为: 7 **************************************** 用jacobi方法解得的结果X[t]为: 1.10 1.20 1.30 2.讨论分析 (1)误差 从上述输出结果中可以看出,当迭代次数k增大时,迭代值x1,y1,z1 会越来越逼近方程组的精确解x=1.0,y=1.2,z=1.3。 (2)收敛性 在本题目中, 用雅可比迭代法和高斯- 塞德尔迭代法分别求解该线性方程组,得到的近似根是收敛的 六、算法评价 优点:迭代法算法简单,编制程序比较容易。 缺点:迭代法要求方程组的系数矩阵有某种特殊性质(譬如是所谓对角占优阵)以保证 过程的收敛性。高斯—塞德尔迭代法比雅可比迭代法收敛快(达到同样的精度所需迭代次 数少),但这个结论,在一定条件下才是对的,甚至有这样的方程组,雅可比方法收敛,而高 斯—塞德尔迭代法却是发散的。在雅可比迭代法求解线性方程组时,只要误差截断设计的 合理,原则上可以得到很正确的解。而通常我们选取设计误差限或设计最大迭代次数的 方法来控制。由于它的准确性,故在实际应用中比较常见,对于解一般线性方程组非常 有效准确。通过该算法以及编程对求解的过程,我们不难发现,雅克比迭代法的优点明 显,计算公式简单,每迭代一次只需计算一次矩阵和向量的乘法,且计算过程中原始矩 阵A始终不变,比较容易并行计算。然而这种迭代方式收敛速度较慢,而且占据的存储空 间较大,所以工程中一般不直接用雅克比迭代法,而用其改进方法。 附: 高斯—赛德尔程序 program G-S implicit none integer::i,j integer::k save k real,parameter::e=0.001 in

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值