12,788
回編集
68行目: | 68行目: | ||
*: 各ワード転送後にCSをトグルするかどうかを指定する。 | *: 各ワード転送後にCSをトグルするかどうかを指定する。 | ||
*: 通常、CSはトランザクション全体で低いままであるが、一部のデバイスでは各ワード間でCSをトグルする必要がある。 | *: 通常、CSはトランザクション全体で低いままであるが、一部のデバイスでは各ワード間でCSをトグルする必要がある。 | ||
<br><br> | |||
== SPI通信の共通クラスの定義 == | |||
SPI通信の設定を以下に示す。<br> | |||
* LSB First | |||
* 3線式SPIモード / 4線式SPIモード | |||
* ループバックモード | |||
* No Chip Select (CS) | |||
* Ready | |||
* CS Change | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
// SpiDevice.hファイル | |||
#include <QObject> | |||
#include <QFile> | |||
#include <QFuture> | |||
#include <QtConcurrent> | |||
#include <sys/ioctl.h> | |||
#include <linux/spi/spidev.h> | |||
#include <fcntl.h> | |||
#include <unistd.h> | |||
class SpiDevice : public QObject | |||
{ | |||
Q_OBJECT | |||
protected: | |||
QString m_devicePath; | |||
public: | |||
enum class Mode { | |||
Mode0 = SPI_MODE_0, | |||
Mode1 = SPI_MODE_1, | |||
Mode2 = SPI_MODE_2, | |||
Mode3 = SPI_MODE_3 | |||
}; | |||
struct Config { | |||
Mode mode = Mode::Mode0; | |||
bool lsbFirst = false; | |||
bool threeWire = false; | |||
bool loopback = false; | |||
bool noCs = false; | |||
bool ready = false; | |||
bool csChange = false; | |||
uint8_t bitsPerWord = 8; | |||
uint32_t speed = 500000; | |||
}; | |||
explicit SpiDevice(const QString& devicePath, QObject* parent = nullptr) : QObject(parent), m_devicePath(devicePath) | |||
{} | |||
bool configure(const Config& config) | |||
{ | |||
QFile spiDevice(m_devicePath); | |||
if (!spiDevice.open(QIODevice::ReadWrite)) { | |||
emit errorOccurred("SPIデバイスを開けませんでした: " + spiDevice.errorString()); | |||
return false; | |||
} | |||
int fd = spiDevice.handle(); | |||
uint8_t mode = static_cast<uint8_t>(config.mode); | |||
if (config.lsbFirst) mode |= SPI_LSB_FIRST; | |||
if (config.threeWire) mode |= SPI_3WIRE; | |||
if (config.loopback) mode |= SPI_LOOP; | |||
if (config.noCs) mode |= SPI_NO_CS; | |||
if (config.ready) mode |= SPI_READY; | |||
if (config.csChange) mode |= SPI_CS_HIGH; | |||
if (ioctl(fd, SPI_IOC_WR_MODE, &mode) < 0 || ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &config.bitsPerWord) < 0 || | |||
ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &config.speed) < 0) { | |||
emit errorOccurred("SPIの設定に失敗しました"); | |||
spiDevice.close(); | |||
return false; | |||
} | |||
spiDevice.close(); | |||
return true; | |||
} | |||
signals: | |||
void errorOccurred(const QString& error); | |||
}; | |||
</syntaxhighlight> | |||
<br><br> | <br><br> | ||
84行目: | 169行目: | ||
#include <fcntl.h> | #include <fcntl.h> | ||
#include <unistd.h> | #include <unistd.h> | ||
#include "SpiDevice.h" | |||
class SpiReader : public | class SpiReader : public SpiDevice | ||
{ | { | ||
Q_OBJECT | Q_OBJECT | ||
private: | private: | ||
std::atomic<bool> m_stopReading{false}; | std::atomic<bool> m_stopReading{false}; | ||
public: | public: | ||
using SpiDevice::SpiDevice; | |||
void startReading(int bufferSize = 1024) | void startReading(int bufferSize = 1024) | ||
107行目: | 191行目: | ||
int fd = spiDevice.handle(); | int fd = spiDevice.handle(); | ||
QByteArray buffer(bufferSize, 0); | QByteArray buffer(bufferSize, 0); | ||
while (!m_stopReading) { | while (!m_stopReading) { | ||
ssize_t ret = read(fd, buffer.data(), buffer.size()); | ssize_t ret = read(fd, buffer.data(), buffer.size()); | ||
if (ret < 0) { | if (ret < 0) { | ||
emit errorOccurred(" | emit errorOccurred("SPIの読み込みに失敗しました"); | ||
break; | break; | ||
} | } | ||
142行目: | 215行目: | ||
signals: | signals: | ||
void dataRead(const QByteArray& data); | void dataRead(const QByteArray& data); | ||
void readingFinished(); | void readingFinished(); | ||
}; | }; | ||
159行目: | 231行目: | ||
SpiReader reader("/dev/spidev0.0"); | SpiReader reader("/dev/spidev0.0"); | ||
SpiDevice::Config config; | |||
config.mode = SpiDevice::Mode::Mode0; | |||
config.lsbFirst = true; | |||
config.threeWire = true; | |||
config.loopback = false; | |||
config.noCs = true; | |||
config.ready = false; | |||
config.csChange = false; | |||
config.bitsPerWord = 8; | |||
config.speed = 1000000; | |||
if (!reader.configure(config) || !writer.configure(config)) { | |||
qDebug() << "SPIデバイスの設定に失敗"; | |||
return -1; | |||
} | |||
QObject::connect(&reader, &SpiReader::dataRead, [](const QByteArray& data) { | QObject::connect(&reader, &SpiReader::dataRead, [](const QByteArray& data) { |