0.前言
由于cubieboard2官方稳定版内核linux-3.4未添加原生spi驱动支持,我们需要为修改内核源码,编译并放入nand中,替换掉原来的uImage镜像,并放入新内核的模块文件。除此之外,还需要修改系统文件,使其完整支持全双工通信。
1.刷入debian系统到nand。(windows下)
首先下载为cubieboard2定制的debian系统,地址为:http://dl.cubieboard.org/software/a20-cubieboard/debian/nand/debian-nand.img.gz
下载Phoenixsuit,通过Phoenixsuit打开下载的镜像。在cubieboard2未接电源的状态下按住FEL按钮的同时通过OTG线接入电脑,在设备管理器将这个未识别的设备安装驱动,指定驱动安装目录为Phoenixsuit的安装目录,确认安装。
然后格式化并刷入镜像。
2.登陆系统
将cubieboard2接入网线,该debian系统默认设为静态ip地址192.168.1.124,你可以通过ssh进入该系统。你也可以通过TTL线从UART进行登陆,修改为DHCP方式,然后从路由器查看IP地址,再登陆。路由器账户名密码为root/cubieboard。
3.修改内核(ubuntu下)
目前linux内核不支持cubieboard2的spi驱动。首先下载内核源码linux-3.4分支:https://github.com/linux-sunxi/linux-sunxi 。然后为内核增加spi支持(不建议),详情请查看 http://www.linuxdiyf.com/linux/21506.html 。这里直接下载已经修改好的spi支持,地址 https://github.com/linanwx/cubieboard2-spi-support 。下载后,将内核目录drivers/spi删除,将下载的spi文件夹放在删除的位置。
4.编译内核(ubuntu下)
准备好arm-linux-gnueabihf-gcc编译器,版本不高于5.0
在内核目录中,使用终端,输入
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- sun7i_defconfig
输入
gedit .config
找到以下选项,并将其改为
CONFIG_SPI=y
CONFIG_SUNXI_NAND_PARTITION=y
CONFIG_SUNXI_NAND=y
输入以下命令开始编译内核
make -j4ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- uImage modules
由于开启了CONFIG_SPI支持和CONFIG_SUNXI_NAND支持,需要进行一系列的设置。当遇到spi support,CONFIG_SPI_SUN7I,CONFIG_SUN7I_SPI_NDMA时,输入y,其他情况输入回车。
检查路径arch/arm/boot下是否有uImage文件
输入以下命令生成内核模块
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- INSTALL_MOD_PATH=output modules_install
检查路径output/lib/modules/3.4.104目录是否产生
5.替换内核(cubieboard2下)
在cubieboard2 中,打开终端,输入
mkdir /media/nanda
mount /dev/nanda /media/nanda
将uImage拷贝至cubieboard2 debian系统的/media/nanda目录覆盖原来内核
使用tar命令打包output/lib/modules/3.4.104 目录,将该文件传入cubieboard2 的 /lib/modules 目录,然后解压
6.检查编译成功
重启,如果系统正常进入,则成功
7.修改系统文件打开SPI,并使其支持全双工SPI(cubieboard2下)
重新挂载/dev/nanda到/media/nanda/ 目录并进入
输入如下命令
bin2fex script.bin script.fex
nano script.fex
找到[spi0_para],将其下面的used改为1,并额外增加如下代码
[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
nano /usr/include/linux/spi/spidev.h
在__u16 delay_usecs;上面一行添加
__u16 interbyte_usecs;
8.测试spi
重启cubieboard2。检查路径/dev下是否存在spidev设备。短接46,48pin脚,管脚图http://docs.cubieboard.org/products/a10_cubieboard/expansion_ports。
新建文本输入如下代码
/*
* SPI testing utility (using spidev driver)
*
* Copyright (c) 2007 MontaVista Software, Inc.
* Copyright (c) 2007 Anton Vorontsov <avorontsov@ru.mvista.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License.
*
* Cross-compile with cross-gcc -I/path/to/cross-kernel/include
*/
#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>
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
static void pabort(const char *s)
{
perror(s);
abort();
}
static const char *device = "/dev/spidev0.0";
static uint8_t mode;
static uint8_t bits = 8;
static uint32_t speed = 500000;
static uint16_t delay;
static void transfer(int fd)
{
int ret;
uint8_t tx[] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x40, 0x00, 0x00, 0x00, 0x00, 0x95,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xDE, 0xAD, 0xBE, 0xEF, 0xBA, 0xAD,
0xF0, 0x0D,
};
uint8_t rx[ARRAY_SIZE(tx)] = {
0,
};
struct spi_ioc_transfer tr = {
.tx_buf = (unsigned long)tx,
.rx_buf = (unsigned long)rx,
.len = ARRAY_SIZE(tx),
.delay_usecs = delay,
.speed_hz = speed,
.bits_per_word = bits,
};
ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
if (ret == 1)
pabort("can't send spi message");
for (ret = 0; ret < ARRAY_SIZE(tx); ret++)
{
if (!(ret % 6))
puts("");
printf("%.2X ", rx[ret]);
}
puts("");
}
static void print_usage(const char *prog)
{
printf("Usage: %s [-DsbdlHOLC3]\n", prog);
puts(" -D --device device to use (default /dev/spidev0.0)\n"
" -s --speed max speed (Hz)\n"
" -d --delay delay (usec)\n"
" -b --bpw bits per word \n"
" -l --loop loopback\n"
" -H --cpha clock phase\n"
" -O --cpol clock polarity\n"
" -L --lsb least significant bit first\n"
" -C --cs-high chip select active high\n"
" -3 --3wireSI/SO signals shared\n");
exit(1);
}
static void parse_opts(int argc, char *argv[])
{
while (1)
{
static const struct option lopts[] = {
{"device", 1, 0, 'D'},
{"speed", 1, 0, 's'},
{"delay", 1, 0, 'd'},
{"bpw", 1, 0, 'b'},
{"loop", 0, 0, 'l'},
{"cpha", 0, 0, 'H'},
{"cpol", 0, 0, 'O'},
{"lsb", 0, 0, 'L'},
{"cs-high", 0, 0, 'C'},
{"3wire", 0, 0, '3'},
{"no-cs", 0, 0, 'N'},
{"ready", 0, 0, 'R'},
{NULL, 0, 0, 0},
};
int c;
c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR", lopts, NULL);
if (c == -1)
break;
switch (c)
{
case 'D':
device = optarg;
break;
case 's':
speed = atoi(optarg);
break;
case 'd':
delay = atoi(optarg);
break;
case 'b':
bits = atoi(optarg);
break;
case 'l':
mode |= SPI_LOOP;
break;
case 'H':
mode |= SPI_CPHA;
break;
case 'O':
mode |= SPI_CPOL;
break;
case 'L':
mode |= SPI_LSB_FIRST;
break;
case 'C':
mode |= SPI_CS_HIGH;
break;
case '3':
mode |= SPI_3WIRE;
break;
case 'N':
mode |= SPI_NO_CS;
break;
case 'R':
mode |= SPI_READY;
break;
default:
print_usage(argv[0]);
break;
}
}
}
int main(int argc, char *argv[])
{
int ret = 0;
int fd;
parse_opts(argc, argv);
fd = open(device, O_RDWR);
if (fd < 0)
pabort("can't open device");
/*
* 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");
printf("spi mode: %d\n", mode);
printf("bits per word: %d\n", bits);
printf("max speed: %d Hz (%d KHz)\n", speed, speed / 1000);
transfer(fd);
close(fd);
return ret;
}
编译该文件运行,若输出结果如下则修改成功
spi mode: 0
bits per word: 8
max speed: 500000 Hz (500 KHz)
FF FF FF FF FF FF
40 00 00 00 00 95
FF FF FF FF FF FF
FF FF FF FF FF FF
FF FF FF FF FF FF
DE AD BE EF BA AD
F0 0D