文章

使用 c++ 实现一个 SPI 接口操作类

使用 c++ 实现一个 SPI 接口操作类

记录一下在项目中我常用到的 SPI 接口操作代码。

串口代码

spi.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#ifndef __SPI_H__
#define __SPI_H__

#include <fcntl.h>
#include <linux/spi/spidev.h>
#include <sys/ioctl.h>
#include <unistd.h>

#include <cstdint>
#include <cstring>
#include <string>
#include <vector>

class Spi {
public:
    explicit Spi(
        const std::string &dev_node = "/dev/spidev0.0",
        uint8_t mode = SPI_MODE_0,
        uint32_t speed = 1000000,
        uint8_t bits = 8)
        : _dev_node(dev_node),
          _mode(mode),
          _speed(speed),
          _bits(bits),
          _fd(-1),
          _is_open(false) {
    }

    ~Spi() {
        close();
    }

    void open() {
        _fd = ::open(_dev_node.c_str(), O_RDWR);
        if (_fd < 0) {
            return;
        }

        // 设置SPI参数
        if (ioctl(_fd, SPI_IOC_WR_MODE, &_mode) < 0
            || ioctl(_fd, SPI_IOC_WR_MAX_SPEED_HZ, &_speed) < 0
            || ioctl(_fd, SPI_IOC_WR_BITS_PER_WORD, &_bits) < 0) {
            ::close(_fd);
            _fd = -1;
            _is_open = false;
            return;
        }

        _is_open = true;
        return;
    }

    void close() {
        if (_fd >= 0) {
            ::close(_fd);
        }
        _fd = -1;
        _is_open = false;
    }

    int32_t write(uint8_t *tx_data, uint32_t len) {
        if (_fd < 0) {
            open();
        }

        if (!_is_open) {
            return -1;
        }
        return spi_transfer(tx_data, nullptr, len);
    }

    int32_t read(uint8_t *rx_data, uint32_t len) {
        if (_fd < 0) {
            open();
        }
        if (!_is_open || len == 0) {
            return -1;
        }

        std::vector<uint8_t> tx_data(len, 0);
        return spi_transfer(tx_data.data(), rx_data, len);
    }

    int32_t spi_transfer(uint8_t *tx_buf, uint8_t *rx_buf, uint32_t len) {
        if (_fd < 0) {
            open();
        }
        spi_ioc_transfer tr = {};
        tr.tx_buf = reinterpret_cast<unsigned long long>(tx_buf);
        tr.rx_buf = reinterpret_cast<unsigned long long>(rx_buf);
        tr.len = len;
        tr.speed_hz = _speed;
        tr.delay_usecs = 0;
        tr.bits_per_word = _bits;
        tr.cs_change = 0; // 保持CS激活

        if (ioctl(_fd, SPI_IOC_MESSAGE(1), &tr) < 0) {
            return -1;
        }
        return 0;
    }

private:
    bool _is_open;
    int32_t _fd;
    uint8_t _mode;
    uint32_t _speed;
    uint8_t _bits;
    std::string _dev_node;
};
#endif // __SPI_H__

使用示例

main.cpp

1
2
3
4
5
6
7
8
9
#include "spi.h"

int main() {
    Spi spi("/dev/spidev0.1", SPI_MODE_0, 1000000, 8);
    spi.open();
    // TODO:
    spi.close();
    return 0;
}
本文由作者按照 CC BY 4.0 进行授权