/**********************************************************************
* linux SPI bus demo hacking
* 说明:
* 本文主要解析linux应用程序如何使用SPI总线和设备通信。
*
* 2016-3-28 深圳 南山平山村 曾剑锋
*********************************************************************/ // 参考文档:
// 1. getopt_long
// http://baike.baidu.com/link?url=6KJogehaQx-6OWyU0882g2P5Fdp-NoKBPJOBGYbx-gQIT6km2myaonw2nOheKsSoMXtDQTqsuVmTwS7trQ5vxq
// 2. Linux Signal (10): abort函数
// http://blog.csdn.net/yylklshmyt20090217/article/details/4234237
// 3. 用户空间的spi驱动
// http://blog.csdn.net/liangxiaozhang/article/details/7601880 /*
* 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();
} // 默认spi设备节点
static const char *device = "/dev/spidev1.0";
static uint8_t mode;
static uint8_t bits = ;
static uint32_t speed = ;
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,
};
// 接收的数据,接收的数据长度和发送的数据长度是一样的,初始化为0。
uint8_t rx[ARRAY_SIZE(tx)] = {, };
// 发送数据结构体
struct spi_ioc_transfer tr = {
.tx_buf = (unsigned long)tx, // 写数据缓冲
.rx_buf = (unsigned long)rx, // 读数据缓冲
.len = ARRAY_SIZE(tx), // 缓冲的长度
.delay_usecs = delay, // 两个spi_ioc_transfer之间的延时
.speed_hz = speed, // 通信的时钟频率
.bits_per_word = bits, // 字长(比特数)
}; // 发送数据
ret = ioctl(fd, SPI_IOC_MESSAGE(), &tr);
if (ret < )
pabort("can't send spi message"); // 显示输出发送buf的数据内容
for (ret = ; ret < ARRAY_SIZE(tx); ret++) {
if (!(ret % ))
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/spidev1.1)\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();
} static void parse_opts(int argc, char *argv[])
{
while () { /**
* struct option {
* const char *name;
* int has_arg;
* int *flag;
* int val;
* };
* The meanings of the different fields are:
* name is the name of the long option.
*
* has_arg
* is: no_argument (or 0) if the option does not take an
* argument; required_argument (or 1) if the option requires an
* argument; or optional_argument (or 2) if the option takes an
* optional argument.
*
* flag specifies how results are returned for a long option. If flag
* is NULL, then getopt_long() returns val. (For example, the
* calling program may set val to the equivalent short option
* character.) Otherwise, getopt_long() returns 0, and flag
* points to a variable which is set to val if the option is
* found, but left unchanged if the option is not found.
*
* val is the value to return, or to load into the variable pointed
* to by flag.
*
*/
static const struct option lopts[] = {
{ "device", , , 'D' },
{ "speed", , , 's' },
{ "delay", , , 'd' },
{ "bpw", , , 'b' },
{ "loop", , , 'l' },
{ "cpha", , , 'H' },
{ "cpol", , , 'O' },
{ "lsb", , , 'L' },
{ "cs-high", , , 'C' },
{ "3wire", , , '' },
{ "no-cs", , , 'N' },
{ "ready", , , 'R' },
{ NULL, , , },
};
int c; /**
* 1. 函数中的argc和argv通常直接从main()的两个参数传递而来。
* 2. 字符串optstring可以下列元素:
* 1.单个字符,表示选项,
* 2.单个字符后接一个冒号:表示该选项后必须跟一个参数。参数紧跟在选项后或者以空格隔开。该参数的指针赋给optarg。
* 3 单个字符后跟两个冒号,表示该选项后可以有参数也可以没有参数。如果有参数,参数必须紧跟在选项后不能以空格隔开。该参数的指针赋给optarg。(这个特性是GNU的扩张)。
* 3. 参数longopts,其实是一个结构的实例。
* 4. 参数longindex,表示当前长参数在longopts中的索引值。
* 5. 给个例子:
* struct option long_options[] = {
* {"a123", required_argument, 0, 'a'},
* {"c123", no_argument, 0, 'c'},
* }
* 现在,如果命令行的参数是-a 123,那么调用getopt_long()将返回字符'a',并且将字符串123由optarg返回(注意注意!字符串123由optarg带回!optarg不需要定义,在getopt.h中已经有定义),那么,如果命令行参数是-c,那么调用getopt_long()将返回字符'c',而此时,optarg是null。最后,当getopt_long()将命令行所有参数全部解析完成后,返回-1。
*/
c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR", lopts, NULL); // 这里表示解析参数已经到了最后一个,会跳出while循环
if (c == -)
break; switch (c) {
case 'D':
device = optarg; // getopt_long函数将参数指针放在optarg中
break;
case 's':
speed = atoi(optarg); // 将optarg字符串转成int型数字
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 '':
mode |= SPI_3WIRE;
break;
case 'N':
mode |= SPI_NO_CS;
break;
case 'R':
mode |= SPI_READY;
break;
default:
print_usage(argv[]);
break;
}
}
} int main(int argc, char *argv[])
{
int ret = ;
int fd; // 参数解析
parse_opts(argc, argv); // 打开设备
fd = open(device, O_RDWR);
if (fd < )
pabort("can't open device"); /*
* spi mode
* 设置spi模式
*/
ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
if (ret == -)
pabort("can't set spi mode"); // 读取spi模式
ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
if (ret == -)
pabort("can't get spi mode"); /*
* bits per word
* 设置spi字节位数
*/
ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
if (ret == -)
pabort("can't set bits per word"); // 读取spi字节位数
ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
if (ret == -)
pabort("can't get bits per word"); /*
* max speed hz
* 设置spi最大速率
*/
ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
if (ret == -)
pabort("can't set max speed hz"); // 设置spi最大速率
ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
if (ret == -)
pabort("can't get max speed hz"); // 显示设置的spi相关参数,这里输出的都是设置了之后,又重新读回来的值,
// 便于确认你设置的值和真是程序运行的值是否有差异。
printf("spi mode: %d\n", mode);
printf("bits per word: %d\n", bits);
printf("max speed: %d Hz (%d KHz)\n", speed, speed/); // 发送数据
transfer(fd); // 关闭设备节点
close(fd); return ret;
}

linux SPI bus demo hacking的更多相关文章

  1. linux watchdog demo hacking

    /********************************************************************** * linux watchdog demo hackin ...

  2. Linux SocketCan client server demo hacking

    /*********************************************************************** * Linux SocketCan client se ...

  3. Linux spi驱动分析(二)----SPI核心(bus、device_driver和device)

    一.spi总线注册 这里所说的SPI核心,就是指/drivers/spi/目录下spi.c文件中提供给其他文件的函数,首先看下spi核心的初始化函数spi_init(void).程序如下: 点击(此处 ...

  4. I.MX6 ar1020 SPI device driver hacking

    /************************************************************************************ * I.MX6 ar1020 ...

  5. ti processor sdk linux am335x evm Makefile hacking

    # # ti processor sdk linux am335x evm Makefile hacking # 说明: # 本文主要对TI的sdk中的Makefile脚本进行解读,是为了了解其工作机 ...

  6. Linux power supply class hacking

    /*************************************************************************** * Linux power supply cl ...

  7. Linux Spi驱动移植小结

    2012-01-07 22:21:29 效果图: 理论学习后,主要是linux中spi子系统设备框架的了解后,主控制器与设备分离的思想,那么我要开始动手了. 1,  make menuconfig添加 ...

  8. am335x Qt SocketCAN Demo hacking

    /*********************************************************************************** * am335x Qt Soc ...

  9. I.MX6 Linux I2C device& driver hacking

    /******************************************************************************************* * I.MX6 ...

随机推荐

  1. oracle游标小试

    有时候需要大面积的修改数据,这个时候用循环语句效率不高.而临时表又不能满足点对点修改的时候,游标似一种不错的选择(PS:好像游标也是为循环而生的吧) 现在有两张表 t1(ryid number,nam ...

  2. PowerDesigner 非数值默认值时会自动增加单引单

    在PowerDesigner中,如果默认值是非数值型的,那么 PowerDesigner 会默认加上单引号 因此我们需要把这个默认的单引号干掉,如果是需要设置字符串默认值的时候,就手工加上 单引号 即 ...

  3. GridView ItemCommand

    GridView ItemCommand中取某行某列的值方法,这里提供两个常用的: 一.用CommandArgument属性取值页面如下: <asp:TemplateColumn HeaderT ...

  4. 【git】借助github学习成果

    1.创建分支 git branch dev   //创建分支 git checkout dev  //切换分支 或者用一句  git checkout -b dev 删除一个分支  git check ...

  5. redis参考

    www.redis.cn www.redis.io http://blog.nosqlfan.com/ 可以移步http://try.redis.io/进行实验命令 Redis 设计与实现(第一版) ...

  6. sql中的inner join, left join, right join的区别

    下面介绍一下 inner join, left join, right join这者之间的区别 现在我假设有A表和B表 left join select * from A a left join B ...

  7. linux驱动系列之arm汇编

    在arm平台学习linux时,会遇到arm汇编指令,arm汇编指令与8086汇编指令很多地方都不同,在此记下来以免后面忘了,同时在学习了汇编指令之后分析一些汇编指令编写的代码. 一.相对跳转指令b.b ...

  8. c++ 异常处理 assert | try

    #include <iostream> #include <cassert> using namespace std; int main() { ; assert(i == ) ...

  9. 写作技巧--Simile明喻

  10. UNITY3D使用NGUI制作自适应UI的总结

    原地址:http://www.cnitblog.com/updraft/archive/2013/11/12/88801.html 制作自适应的几个方法1. 使用 UIROOT 里设置自定义高度的方法 ...