Skip to content

Instantly share code, notes, and snippets.

@patrickelectric
Last active December 10, 2024 12:44
Show Gist options
  • Save patrickelectric/a2751a4e622ef84473364ebc36bcda87 to your computer and use it in GitHub Desktop.
Save patrickelectric/a2751a4e622ef84473364ebc36bcda87 to your computer and use it in GitHub Desktop.
Test SPI
#include <iostream>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/gpio.h>
#include <linux/spi/spidev.h>
#include <cstring>
#define GPIO_CHIP_PATH "/dev/gpiochip4"
#define SPI_DEVICE_PATH "/dev/spidev1.0"
#define GPIO_CS_LINE 16
int main() {
int chip_fd = open(GPIO_CHIP_PATH, O_RDWR | O_CLOEXEC);
if (chip_fd < 0) {
perror("Failed to open GPIO chip");
return -1;
}
// Request the GPIO line using the GPIO v2 interface
struct gpio_v2_line_request req;
memset(&req, 0, sizeof(req));
req.offsets[0] = GPIO_CS_LINE; // The GPIO line offset
req.num_lines = 1;
req.config.flags = GPIO_V2_LINE_FLAG_OUTPUT;
req.config.num_attrs = 0;
if (ioctl(chip_fd, GPIO_V2_GET_LINE_IOCTL, &req) < 0) {
perror("Failed to get line handle");
close(chip_fd);
return -1;
}
int spi_fd = open(SPI_DEVICE_PATH, O_RDWR);
if (spi_fd < 0) {
perror("Failed to open SPI device");
close(req.fd);
close(chip_fd);
return -1;
}
// Configure SPI settings
uint8_t mode = SPI_MODE_0;
if (ioctl(spi_fd, SPI_IOC_WR_MODE, &mode) < 0) {
perror("Failed to set SPI mode");
close(spi_fd);
close(req.fd);
close(chip_fd);
return -1;
}
uint8_t bits_per_word = 8;
if (ioctl(spi_fd, SPI_IOC_WR_BITS_PER_WORD, &bits_per_word) < 0) {
perror("Failed to set bits per word");
close(spi_fd);
close(req.fd);
close(chip_fd);
return -1;
}
uint32_t speed = 1000000;
if (ioctl(spi_fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed) < 0) {
perror("Failed to set max speed Hz");
close(spi_fd);
close(req.fd);
close(chip_fd);
return -1;
}
// Prepare to control the CS line
struct gpio_v2_line_values values;
memset(&values, 0, sizeof(values));
values.mask = 1 << 0; // Only one line, line 0 in our request
// Pull CS low
values.bits = 0; // Set line 0 to 0 (CS low)
if (ioctl(req.fd, GPIO_V2_LINE_SET_VALUES_IOCTL, &values) < 0) {
perror("Failed to set CS low");
close(spi_fd);
close(req.fd);
close(chip_fd);
return -1;
}
// Prepare SPI transfer buffers
uint8_t tx_buffer[2];
uint8_t rx_buffer[2];
tx_buffer[0] = 0x75 | 0x80; // Read command for WHO_AM_I register
tx_buffer[1] = 0x00; // Dummy byte to receive data
struct spi_ioc_transfer spi_transfer;
memset(&spi_transfer, 0, sizeof(spi_transfer));
spi_transfer.tx_buf = reinterpret_cast<unsigned long>(tx_buffer);
spi_transfer.rx_buf = reinterpret_cast<unsigned long>(rx_buffer);
spi_transfer.len = 2;
spi_transfer.speed_hz = speed;
spi_transfer.bits_per_word = bits_per_word;
spi_transfer.delay_usecs = 0;
// Perform the SPI transfer
int ret = ioctl(spi_fd, SPI_IOC_MESSAGE(1), &spi_transfer);
if (ret < 1) {
perror("Failed to perform SPI transfer");
close(spi_fd);
close(req.fd);
close(chip_fd);
return -1;
}
// Pull CS high
values.bits = 1 << 0; // Set line 0 to 1 (CS high)
if (ioctl(req.fd, GPIO_V2_LINE_SET_VALUES_IOCTL, &values) < 0) {
perror("Failed to set CS high");
close(spi_fd);
close(req.fd);
close(chip_fd);
return -1;
}
// Read and verify the WHO_AM_I register
uint8_t who_am_i = rx_buffer[1];
std::cout << "WHO_AM_I register value: 0x" << std::hex << static_cast<int>(who_am_i) << std::dec << std::endl;
if (who_am_i == 0x12) {
std::cout << "WHO_AM_I value is correct." << std::endl;
} else {
std::cout << "WHO_AM_I value is incorrect." << std::endl;
}
// Cleanup
close(spi_fd);
close(req.fd);
close(chip_fd);
return 0;
}
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/spi/spidev.h>
int main() {
int fd = open("/dev/spidev1.2", O_RDWR);
if (fd < 0) return -1;
uint8_t mode = SPI_MODE_3; // Try SPI_MODE_3 if SPI_MODE_0 returns 0x00
ioctl(fd, SPI_IOC_WR_MODE, &mode);
uint8_t bits = 8;
ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
uint32_t speed = 1000000;
ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
// WHO_AM_I register: 0x75. For read: set MSB = 1 (0x80)
uint8_t tx[2], rx[2];
memset(tx, 0, sizeof(tx));
memset(rx, 0, sizeof(rx));
tx[0] = 0x75 | 0x80;
tx[1] = 0x00; // dummy byte
struct spi_ioc_transfer tr[2] = {};
// Send address
tr[0].tx_buf = (unsigned long)&tx[0];
tr[0].rx_buf = (unsigned long)&rx[0];
tr[0].len = 1;
tr[0].speed_hz = speed;
tr[0].bits_per_word = bits;
// Read data
tr[1].tx_buf = (unsigned long)&tx[1];
tr[1].rx_buf = (unsigned long)&rx[1];
tr[1].len = 1;
tr[1].speed_hz = speed;
tr[1].bits_per_word = bits;
// Perform transaction
if (ioctl(fd, SPI_IOC_MESSAGE(2), &tr) < 1) {
close(fd);
return -1;
}
close(fd);
printf("WHO_AM_I: 0x%02X\n", rx[1]);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment