I have a Jetson Orin Nano, and I’m trying to communicate with a device via SPI. I used jetson-io.py to configure pins 19,21,23,24,26 for SPI and rebooted. I’m using the Linux spidev driver (/dev/spidev0.0), and I’ve written my own program to perform a loopback test.
When idle:
- The CS signal (pin 24) is high at 3.4 volts (correct)
- The CLK signal (pin 23) is low (correct)
- The MOSI signal (pin 19) is low (correct)
- The MISO signal (pin 21) is low (correct)
Next, I run a loop where I’m streaming 5 bytes of 0xff back to back. I don’t have a scope, so I’m having to use a multimeter. Here’s what I get:
- The CS signal averages about 2.5 volts. It should be low most of the time, but evidently it’s not.
- The CLK signal is averaging about 1 volt, which seems about right, albeit a bit low.
- When the output data is 0xff, the MOSI signal is averaging less than 0.1 volts, but it should be high most of the time.
- When the output data is zero, the MOSI signal is about the same, but it should be zero all of the time.
- The MISO signal is at zero, which is right, since it’s open and pulled down by the SoC.
I’m doing all of this because when I connect MOSI and MISO together, I should read back what I’m sending, but instead, I get garbage. But it’s not total garbage. When the data written is all 255, then what I get back is mostly high values, but with lots of bits randomly zero. When the data written is all 0, then what I get back is mostly 0, with lots of bits being 1’s.
I’m running at 1kHz, so there shouldn’t be any signal integrity issues.
Here’s the test code:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>
#include <assert.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>
int configure_spi(int fd)
{
int ret;
char mode = SPI_MODE_3;
char bits = 8;
int speed = 1000;
char lsbfirst = 0;
ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
if(ret < 0){
perror("SPI_IOC_WR_MODE");
printf("can't set spi mode 'SPI_IOC_WR_MODE' %d\n", ret);
return 1;
}
ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
if(ret < 0){
printf("can't set spi mode 'SPI_IOC_RD_MODE'\n");
return 1;
}
ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
if(ret < 0){
printf("can't set bits per word 'SPI_IOC_WR_BITS_PER_WORD'\n");
return 1;
}
ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
if(ret < 0){
printf("can't get bits per word 'SPI_IOC_RD_BITS_PER_WORD'\n");
return 1;
}
ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
if(ret < 0){
printf("can't set max speed hz 'SPI_IOC_WR_MAX_SPEED_HZ'\n");
return 1;
}
ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
if(ret < 0){
printf("can't get max speed hz 'SPI_IOC_RD_MAX_SPEED_HZ'\n");
return 1;
}
ret = ioctl(fd, SPI_IOC_WR_LSB_FIRST, &lsbfirst);
if(ret < 0){
printf("can't set max speed hz 'SPI_IOC_WR_MAX_SPEED_HZ'\n");
return 1;
}
ret = ioctl(fd, SPI_IOC_RD_LSB_FIRST, &lsbfirst);
if(ret < 0){
printf("can't get max speed hz 'SPI_IOC_RD_MAX_SPEED_HZ'\n");
return 1;
}
printf("spi mode: %d\n", mode);
printf("bits per word: %d\n", bits);
printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000);
printf("lsbfirst: %d\n", lsbfirst);
return 0;
}
int datagram(int fd, uint8_t *tbuf, uint8_t *rbuf, size_t len)
{
struct spi_ioc_transfer xfer[1];
memset(xfer, 0, sizeof(xfer));
xfer[0].tx_buf = (unsigned long) tbuf;
xfer[0].rx_buf = (unsigned long) rbuf;
xfer[0].len = len;
xfer[0].speed_hz = 1000;
xfer[0].bits_per_word = 8;
// printf("tx: ");
// for (int i=0; i<len; i++) printf("%02x ", tbuf[i]);
// printf("\n");
// printf("-- %llx %llx %d %d %d, fd=%d\n", xfer[0].tx_buf, xfer[0].rx_buf, xfer[0].len, xfer[0].speed_hz, xfer[0].bits_per_word, fd);
int ret = ioctl(fd, SPI_IOC_MESSAGE(1), xfer);
if(ret < 0){
perror("Error");
printf("SPI_IOC_MESSAGE failed.. %d\n", ret);
return -1;
}
// printf("rx: ");
// for (int i=0; i<len; i++) printf("%02x ", rbuf[i]);
// printf("\n");
return 0;
}
int main()
{
int fd = open("/dev/spidev0.0", O_RDWR);
global_fd = fd;
printf("fd=%d\n", fd);
configure_spi(fd);
uint8_t rbuf[5];
// uint8_t tbuf[5] = {1, 2, 3, 4, 5};
uint8_t tbuf[5] = {255, 255, 255, 255, 255};
memset(rbuf, 0, 5);
while (1)
datagram(fd, tbuf, rbuf, 5);
}