1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > 【Cubieboard2】配置编译内核支持SPI全双工通信驱动

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

时间:2021-12-16 04:06:45

相关推荐

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

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

2,重新编译配置内核

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

或者直接git

git clone git:///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=yCONFIG_SUN7I_SPI_NDMA=y

7、编译内核:

make -j 4 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- uImage modulesmake 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 = 1spi_cs_bitmap = 1spi_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 = 100000bus_num = 0chip_select = 0mode = 0full_duplex = 1manual_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: -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_DEBUGint 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_DEBUGint 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_DEBUGint 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");elsepr_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");}elsepr_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-/A20/PIO

/products/a10_cubieboard/expansion_ports

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

/detail/u010352603/9548040

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。