linux spi 设备节点 读写

本文记录spi设备节点的操作方法。

SPI总线设备文件名通常为/dev/spidevN.P(N=0、1、2……,P=0、1、2……),

其中N表示第几路SPI总线,而P表示在该路SPI总线中使用哪个CS信号线。

参考链接:

  http://www.wzaobao.com/p/l5079K.html

  http://www.emcraft.com/stm32f429discovery/accessing-spi-devices-in-linux

  http://blog.csdn.net/yuanlulu/article/details/6320740

程序

kernel/Documentation/spi/spidev_test.c

编译之后,MISO和MOSI连接,能够收到发送的数据。

#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/spidev1.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/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(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);

    while(1)
    {
        transfer(fd);
        sleep(1);
    }

    close(fd);

    return ret;
}

Tony Liu

2016-10-26, Shenzhen

SPI(Serial Peripheral Interface)是一种串行通信协议,用于在微控制器和外部设备之间传输数据。在Linux系统中,我们可以通过设备SPI节点实现读写。下面是一些基本的步骤: 1. 打开SPI设备节点,例如/dev/spidev0.0。 2. 配置SPI设备的工作模式、传输速率、数据位数等参数。 3. 准备要发送的数据,并将其写入SPI设备的发送缓冲区。 4. 启动SPI传输,将数据从发送缓冲区发送到接收缓冲区。 5. 读取接收缓冲区中的数据。 6. 关闭SPI设备节点。 下面是一个简单的示例程序,演示如何通过SPI节点实现读写: ``` #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> #include <sys/ioctl.h> #include <linux/spi/spidev.h> int main() { int fd; unsigned char tx_buf[3] = {0x01, 0x02, 0x03}; unsigned char rx_buf[3] = {0}; fd = open("/dev/spidev0.0", O_RDWR); if (fd < 0) { perror("open"); exit(1); } // 配置SPI设备参数 unsigned int speed = 1000000; // 传输速率为1MHz unsigned char mode = 0; // 工作模式为0 unsigned char bits = 8; // 数据位数为8 struct spi_ioc_transfer tr = { .tx_buf = (unsigned long)tx_buf, .rx_buf = (unsigned long)rx_buf, .len = 3, .speed_hz = speed, .bits_per_word = bits, .cs_change = 1, }; ioctl(fd, SPI_IOC_WR_MODE, &mode); ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits); ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed); // 启动SPI传输 int ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr); if (ret < 0) { perror("ioctl"); exit(1); } // 读取接收缓冲区中的数据 printf("Received: %02x %02x %02x\n", rx_buf[0], rx_buf[1], rx_buf[2]); close(fd); return 0; } ``` 在这个示例程序中,我们使用了spi_ioc_transfer结构体来配置SPI设备参数和进行数据传输。在ioctl函数中,我们使用了SPI_IOC_WR_MODE、SPI_IOC_WR_BITS_PER_WORD和SPI_IOC_WR_MAX_SPEED_HZ三个宏来设置工作模式、数据位数和传输速率。最后,我们使用了SPI_IOC_MESSAGE宏启动SPI传输,并读取接收缓冲区中的数据。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值