/**********************************************************************
* 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. unity3d 延迟处理方法

    Invoke("方法名", 多少秒后执行); InvokeRepeating("方法名", 多少秒后执行,开始执行后隔多长时间再次执行一次); CancelIn ...

  2. php + mysql + sphinx 的全文检索(2)

    简单 使用php api 去查询 sphinx 的索引数据 $sphinx = new SphinxClient();                 $sphinx->SetServer (  ...

  3. (转)《深入理解java虚拟机》学习笔记8——Tomcat类加载器体系结构

    Tomcat 等主流Web服务器为了实现下面的基本功能,都实现了不止一个自定义的类加载器: (1).部署在同一个服务器上的两个web应用程序所使用的java类库可以相互隔离. (2).部署在同一个服务 ...

  4. java 构造函数

    1.public className(){}. 2.名称与类名相同,无返回值,无返回类型,void也不行.(就是上边的形式,除了可以有参数). 3.有0个或多个参数. 4.每个类都至少有一个const ...

  5. 【BZOJ 1031】[JSOI2007]字符加密Cipher

    Description 喜欢钻研问题的JS 同学,最近又迷上了对加密方法的思考.一天,他突然想出了一种他认为是终极的加密办法:把需要加密的信息排成一圈,显然,它们有很多种不同的读法.例如下图,可以读作 ...

  6. 关于mapreduce过程中出现的错误:Too many fetch-failures

    Reduce task启动后第一个阶段是shuffle,即向map端fetch数据.每次fetch都可能因为connect超时,read超时,checksum错误等原因而失败.Reduce task为 ...

  7. HTTP verb的安全性和幂等性

    Http协议规定了不同方法的安全特性和幂等特性,作为服务提供者的服务器必需为客户端提供这些特性. 安全性,仅指该方法的多次调用不会产生副作用,不涉及传统意义上的“安全”,这里的副作用是指资源状态.即, ...

  8. Workspace in use or cannot be created, choose a different one.--错误解决办法

    eclipse 使用一段时间后,有时会因为一些故障自己就莫名奇妙的关闭了,再打开时有时没有问题,有时有会提示错误 Workspace Unavailable: 原因:出现这种情况一般是workspac ...

  9. jsp的静态包含与动态包含:<%@ include file="" %>和<jsp:include page=""></jsp:include>区别与分析

    <%@ include file="" %>是将文件原封不动的copy进现有的文件中,像是拼接好后,再编译成为servlet运行. <jsp:include pa ...

  10. SQLite数据库简介(转)

    大家好,今天来介绍一下SQLite的相关知识,并结合Java实现对SQLite数据库的操作. SQLite是D.Richard Hipp用C语言编写的开源嵌入式数据库引擎.它支持大多数的SQL92标准 ...