/**********************************************************************
* 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. Python数据结构————二叉查找树的实现

    对于二叉查找树的每个节点Node,它的左子树中所有的关键字都小于Node的关键字,而右子树中的所有关键字都大于Node的关键字. 二叉查找树的平均深度是O(log N). 1.初始化 class Bi ...

  2. (转)linux性能优化总结

    感谢博客http://sillycat.iteye.com提供的资料 linux性能检查(一)介绍和CPU 通常监控的子系统有: CPU Memory IO Network 应用类型 IO相关,处理大 ...

  3. WPF系列

    一.ListView绑定数据源XML //前端代码 1 <Window x:Class="ListView读取XML数据.MainWindow" xmlns="ht ...

  4. html input type="button" 页面跳转

    <div class="message_text"> <p>你的申请已提交,请耐心等候哦!~</p><br /> <input ...

  5. 制作滚动视图(ScrollView)

    怎样判断是否应当使用滚动视图 所谓的滚动视图,是指一个可以滑动的视窗,视窗大小和位置固定不变,视窗内的内容用户可以通过手指滑动或者拖动滚动天来进行滚动浏览. 滚动视图的目的是为了解决同类内容过多,一个 ...

  6. crontab定时任务中文乱码问题

    手动执行都很正常的的脚本,添加到定时任务中日志文件全是乱码经过多方查证终于找到了原因! crontab启动的任务没有获取系统的环境变量,导致中文乱码解决办法:   在执行的脚步中添加编码方式或者添加对 ...

  7. 高仿猫眼电影选座(选票)模块-b

    上图看效果先: 1)画座位图其实不是很难一般数据都会给坐标,将坐标对应座位画出来就可以了,主要是开场动画要设置默认大小,还有座位图的数量也不是固定的,所以在初始化座位图的时侯就默认算出了整个座位图的大 ...

  8. Contest2037 - CSU Monthly 2013 Oct(中南大学2013年10月月赛水题部分题解)

    Problem A: Small change 题解:http://www.cnblogs.com/crazyapple/p/3349469.html Problem B: Scoop water 题 ...

  9. Tiny6410 LED字符设备驱动

    1.查看用户手册 led1.led2.led3.led4 连接的分别是 GPK4.GPK5.GPK6.GPK7 2.查询6410芯片手册 下面还需要3个步骤: 1.设置GPIO为OUTPUT. 将GP ...

  10. AlphaGo 已经战胜了李世石,而你还不知道什么是机器学习?

    谷歌人工智能 AlphaGo 与韩国棋手李世石 3 月 15 日进行了最后一场较量,最终比赛结果为 AlphaGo 4:1 胜李世石,人机围棋大战巅峰对决至此落幕.我不知道大家有没有被震撼到,反正我的 ...