Cubieboard2 添加SPI 驱动支持

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://blog.csdn.net/u010352603/article/details/51657265# 。这里直接下载已经修改好的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 --3wire    SI/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 
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,999评论 4 368
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,102评论 1 302
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 110,709评论 0 250
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,439评论 0 217
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,846评论 3 294
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,881评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,062评论 2 317
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,783评论 0 205
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,517评论 1 248
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,762评论 2 253
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,241评论 1 264
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,568评论 3 260
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,236评论 3 241
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,145评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,941评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,965评论 2 283
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,802评论 2 275

推荐阅读更多精彩内容

  • Ubuntu的发音 Ubuntu,源于非洲祖鲁人和科萨人的语言,发作 oo-boon-too 的音。了解发音是有意...
    萤火虫de梦阅读 98,558评论 9 468
  • linux资料总章2.1 1.0写的不好抱歉 但是2.0已经改了很多 但是错误还是无法避免 以后资料会慢慢更新 大...
    数据革命阅读 12,034评论 2 34
  • 姓名:吴兆阳 学号:14020199009 转自韦东山 嵌牛导读:对嵌入式初学者,没有足够的视野选择一个合适投入方...
    吴兆阳阅读 2,350评论 0 4
  • Linux系统的使用与开发中,内核与驱动是比较重要的一块;而驱动开发类似系统编程,用到的是内核函数。驱动开发难点在...
    jkCodic阅读 8,646评论 0 7
  • 最近工作安排的比较紧张,得到专栏的很多期知识点都落下了,可是一到晚上还是很累并不想学习了!可能最近真的是懈怠了,竟...
    超人在进化阅读 233评论 0 1