/**********************************************************************
* 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. Spark Streaming揭秘 Day24 Transformation和action图解

    Spark Streaming揭秘 Day24 Transformation和action图解 今天我们进入SparkStreaming的数据处理,谈一下两个重要的操作Transfromation和a ...

  2. sizeof的用法的一些归纳

    1 sizeof 是运算符,不是函数 2 sizeof 不能求得void类型的长度,能求得 void*类型的指针的长度 sizeof(void) 会导致编译错误.因为声明一个变量的最重要的作用就是告诉 ...

  3. FFT Golang 实现

    最近项目要用到快速傅立叶变换,自己写了个算法,测试了下,性能和精度还可以接受 len,time= 1048576 378.186167ms diff=-0.00000000000225974794 I ...

  4. jquery.prompt.js 弹窗的使用

    /*** * Prompt提示语插件 * 编写时间:2013年4月8号 * version:Prompt.1.0.js * author:小宇<i@windyland.com> ***/ ...

  5. Oracle回收站

    回收站是删除对象使用的存储空间.可以使用实例参数recyclebin禁用回收站,默认是on,可以为某个会话或系统设置为off或on.所有模式都有一个回收站. 当表空间不足时可以自动重用回收站对象占用的 ...

  6. Java 多线程 简单实例 (Runnable)

    1.多线程实例 package second; public class A implements Runnable { public char stat = '*'; public void run ...

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

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

  8. Unity3d之Http通讯GET方法和POST方法

    (一)GET方法 IEnumerator SendGet(string _url) { WWW getData = new WWW(_url); yield return getData; if(ge ...

  9. 微软Hololens设备 浅分析

    微软Hololens的定位是一款MR 设备(Mixed reality).MR与AR的不同我认为是MR能够将真实环境的场景信息与虚拟对象进行完美的融合,它是基于SLAM(SimultaneousLoc ...

  10. 如何修改SVN中的用户名和密码

    删除掉C:\Users\Administrator\Application Data\Subversion\auth\svn.simple文件夹下的文件即可.再次访问时,会弹出要求输入用户名和密码. ...