How to use SPI ?

Hi,

I’m trying to use SPI on my Airprime DK.
I found that I had to remove jumpers J306 to J308 to be able to use SPI on port J200.
But on software side I found no information.
I tried to port a legacy C app, but I got some “Inappropriate ioctl for device” errors.

Is there a sample code somewhere to use SPI for something else than audio ?

Thanks.
Regards.

Hi,
Can you try with the latest framework?
We are planning to launch a new forum specifically for legato (Details will be announced soon). You can post your legato specific issues there :smiley:

Regards,
Moderator

Any news on this? I have been trying to get SPI1 running now for a while on my WP85. SPI1_MOSI and SPI1_SCK looks OK on scope but I cannot set the SPI1_MRDY pin which I use as a slave select to my SPI slave. See my code snippets below.

#include "legato.h"
#include "interfaces.h"
#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/spi/sierra_spidev.h>

#define SPI_CPHA		0x01
#define SPI_CPOL		0x02

#define SPI_MODE_0		(0|0)
#define SPI_MODE_1		(0|SPI_CPHA)
#define SPI_MODE_2		(SPI_CPOL|0)
#define SPI_MODE_3		(SPI_CPOL|SPI_CPHA)

#define SPI_CS_HIGH		0x04
#define SPI_LSB_FIRST		0x08
#define SPI_3WIRE		0x10
#define SPI_LOOP		0x20
#define SPI_NO_CS		0x40
#define SPI_READY		0x80
#define SPI_TX_DUAL		0x100
#define SPI_TX_QUAD		0x200
#define SPI_RX_DUAL		0x400
#define SPI_RX_QUAD		0x800


/*===========================================================================
 * DEFINES
 *=========================================================================*/

#define FAIL_ON_ERROR(expr)   do { le_result_t _result_ = (expr); LE_FATAL_IF(_result_ < 0, #expr " failed with %d", _result_); } while (0)

/*===========================================================================
 * DEFINITIONS
 *=========================================================================*/

#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
static le_timer_Ref_t       spiTimer; ///< Timer for spi reading
static const le_clk_Time_t  spiTimerTime  = { .sec = 2, .usec = 0 };       ///< Time between data monitor ticks

static void pabort(const char *s)
{
	LE_FATAL(s);
}

int32_t	spiFd;
static const char *device = "/dev/nrfPort";
static uint8_t mode;
static uint8_t bits = 8;
static uint32_t speed = 960000;
static uint16_t delay = 10;
static uint8_t length=16;
static uint8_t pattern[16] = {0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,
							  0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xEF};
static uint32_t order;

static void transfer(int fd)
{
	int i,ret;
	uint8_t *tx;
	uint8_t *rx;

	struct spi_ioc_transfer tr;

	memset(&tr, 0, sizeof(tr));

	tr.tx_buf = 0;
	tr.rx_buf = 0;
	tr.len = length;
	tr.delay_usecs = delay;
	tr.speed_hz = speed;
	tr.bits_per_word = bits;
	tr.cs_change = true;

	/* create tx & rx buffers */
	tx=calloc(sizeof(uint8_t),length);
	rx=calloc(sizeof(uint8_t),length);
	for (i=0;i<length-1;i+=ARRAY_SIZE(pattern))
		if ((i+ARRAY_SIZE(pattern)) > length)
			memcpy(tx+i,pattern,length-i);
		else
			memcpy(tx+i,pattern,ARRAY_SIZE(pattern));

	tr.tx_buf=(unsigned long)tx;
	tr.rx_buf=(unsigned long)rx;

	ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
	if (ret < 1)
		pabort("can't send spi message");

	for (ret = 0; ret < length; ret++) {
		if (!(ret % 8))
			LE_INFO(" ");
		LE_INFO("%.2X ", rx[ret]);
	}
	LE_INFO(" ");
}

// -------------------------------------------------------------------------------------------------
/**
 *  Timer handler for spi update
 */
// -------------------------------------------------------------------------------------------------
static void spiTimerHandler(le_timer_Ref_t timerRef)
{
    (void)timerRef;

    //send some dummy data
    transfer(spiFd);

    LE_DEBUG("spiTimerHandler: expired %d", le_timer_GetExpiryCount(timerRef));

}


COMPONENT_INIT
{
	int ret = 0;

	LE_INFO("spiReader:Init");

    spiFd = open(device, O_RDWR);
	if (spiFd < 0)
		pabort("can't open device");

	/*
	 * spi mode
	 */

	mode = 0;

	mode |= SPI_MODE_2;

	//mode |= 0x20;	//SPI_LOOP

	ret = ioctl(spiFd, SPI_IOC_WR_MODE, &mode);
	if (ret == -1)
		pabort("can't set spi mode");

	ret = ioctl(spiFd, SPI_IOC_RD_MODE, &mode);
	if (ret == -1)
		pabort("can't get spi mode");


	/*
	 * bits per word
	 */

	bits = 8;

	ret = ioctl(spiFd, SPI_IOC_WR_BITS_PER_WORD, &bits);
	if (ret == -1)
		pabort("can't set bits per word");

	ret = ioctl(spiFd, SPI_IOC_RD_BITS_PER_WORD, &bits);
	if (ret == -1)
		pabort("can't get bits per word");

	/*
	 * max speed hz
	 */

	speed = 960000;

	ret = ioctl(spiFd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
	if (ret == -1)
		pabort("can't set max speed hz");

	ret = ioctl(spiFd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
	if (ret == -1)
		pabort("can't get max speed hz");

	LE_INFO("spi mode: %d\n", mode);
	LE_INFO("bits per word: %d\n", bits);
	LE_INFO("max speed: %d Hz (%d KHz)\n", speed, speed/1000);
	LE_INFO("LSB first\n");

    spiTimer = le_timer_Create("SPI_TIMER");
    FAIL_ON_ERROR( le_timer_SetHandler(spiTimer, spiTimerHandler));
    FAIL_ON_ERROR( le_timer_SetInterval(spiTimer, spiTimerTime));
    FAIL_ON_ERROR( le_timer_SetRepeat(spiTimer, 0));
    FAIL_ON_ERROR( le_timer_Start(spiTimer));

	//close(spiFd);

}