RoboRIO SPI Configuration

Previously WPILib provided support for configuring the bits per word for SPI. Does anyone know how to do that for the RoboRIO built-in SPI?

I’m having the same problem. The SPI code that worked on our CRios wont work on the RoboRio because of this.

I found a solution. You can use the Linux spidev. It is the standard SPI interface for Linux microcomputers. With it you can set all the low level SPI settings including the bits per word. Documentation can be found here https://www.kernel.org/doc/Documentation/spi/spidev.

This is the code I use to enable the spi port:


/******************************************************************************
 *
 * Initializes the spi
 *
 ******************************************************************************/
void Lights::initSPI()
{
	//SPI setup
	int ret = 0;
	fd = 0;
	fd = open(device, O_RDWR);
	if (fd <0)
	{
		output->printError("can't open device");
	}

	/*************************************************************************************************
	 * spi mode
	 */
	//ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
	//if (ret ==-1)
	//{
	//	output->printError("can't set spi mode");
	//}

	ret = ioctl(fd, SPI_IOC_RD_LSB_FIRST, &msb);
	if (ret ==-1)
	{
		output->printError("can't set spi mode");
	}
	printf("MSB mode: %d
",msb);

	/*
	 * bits per word
	 */
	ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
	if (ret ==-1)
	{
		output->printError("can't set bits per word");
	}

	/*
	 * max speed hz
	 */
	ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
	if (ret ==-1)
	{
		output->printError("can't set max speed hz");
	}

	tr.tx_buf = (unsigned long) master_array;
	tr.rx_buf = (unsigned long) NULL;
	tr.len = total_size *3;
	tr.delay_usecs = delay;
	tr.speed_hz = speed;
	tr.bits_per_word = bits;

	printf("spi mode: %d
", mode);
	printf("bits per word: %d
", bits);
	printf("max speed: %d Hz (%d KHz)
", speed, speed /1000);
}

device is a const char* set to one of the following:


const char *device = "/dev/spidev0.X"; //for the main SPI port with chip select X
const char *device = "/dev/spidev1.0"; //for the SPI port on the Custom Electronics Board

and the rest of the settings in the header are:


//SPI interface
int fd;
struct spi_ioc_transfer tr;
const char *device = "/dev/spidev0.0";
const uint8_t mode = SPI_MODE_0;
const uint8_t msb = 0;
const uint8_t bits = 8;
const uint32_t speed = 800000;

Then to send/receive data I use the following:


/**********************************************************************
 *
 * Sends the frame over SPI
 * 
 **********************************************************************/
void Lights::transmitFrame()
{
	finalizeFrame();
	if ((ioctl(fd, SPI_IOC_MESSAGE(1), &tr)) ==-1)
	{
		output->printError("transmit failed");
	}

	for (uint16_t i = 0; i <segment_cnt; i++)
	{
		segment_bank*->renderFrame();
	}

}

I plan on making a class that will do all of the hard work and posting it on Delphi.*

Have you confirmed that changing this setting actually changes the port behavior? If they removed it from the API I assume it was for a reason.

Yes, we have confirmed it. We ran our LPD-8806 lights off of them and they worked perfectly. The LPD-8806 lights are 8 bits per word and the WPILib API seems to only provides 7 bits per word. With the spidev, we were able to change the output to 8 bits per word.

The old SPI class from the WPI library wasn’t actually SPI. On the CRio it would bit bang the Digital IO ports to act like SPI. The problem with that is the software had to take resources away from other tasks to emulate SPI. The RoboRio has dedicated hardware for SPI so it doesn’t need to take away valuable resources from the rest of the robot. I don’t know why they didn’t put in the bits per word setting into the new SPI class. The only reason I can think of is that a lot of IC’s use 7 bits per word. But that doesn’t explain why they wouldn’t give us the option to change it.