This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Linux/PROCESSOR-SDK-AM335X: SPI performance improvement

Part Number: PROCESSOR-SDK-AM335X


Tool/software: Linux

I am trying to send constant and large amount of bytes with SPI from a Linux embedded system -- am335x (Beaglebone: pocketbeagle version). Thing is, I am trying to increase its transfer rate. I am having trouble when sending several blocks of SPI data using spidev (which uses the MCSPI driver). I am sending blocks of 153kb everytime, but I notice a huge delay in between transfers. Here is a picture of a transfer at 15MHz:

Currently, I am accessing SPI through user-space with the following configuration on spidev (ioctl calls):

// SPI init -- (const char *device, int mode, int bits, int speed)
retv = spi_bus.spi_init(LCD_SPI_DEVICE,0,8,100000000);

And this is my write function:

// write data to SPIdev
int SPI::spi_write(const char *tx_buf, int len)
{
  int retv;

  this->xfer.tx_buf = (uint64_t) tx_buf; // output buffer
  this->xfer.rx_buf = (uint64_t) 0;      // input buffer
  this->xfer.len    = (uint32_t) len;    // length of data to write

  retv = ioctl(this->fd, SPI_IOC_MESSAGE(1), &this->xfer);
  if (retv < 0)
  {
    printf("error in spi_write(): ioctl(SPI_IOC_MESSAGE(1)) return %d", retv);
    return SPI_ERR_WRITE;
  }

  return retv;
}

I did see a slightly improvement when increasing the word length (from 8 bits to 16 bits). In this document I read that the following could help:

1) Modify INITDLY

2) Keep SPIEN Active Mode (FORCE bi)

The way I see it (judging from what the oscilloscope is showing), the most crutial part is INITDLY. Thing is, I have no idea how to modify these registers! I know I need to modify this in the spi-omap2-mcspi.c but I don't exactly know where. 

As I understand in the document, I need to modify MCSPI_MODULCTRL in the mcSPI driver. But again, I don't know where in the code I should modify it (and what to modify!). I'd appreciate any guidance! 

My attempt so far:

I modified the driver with the following:

static void omap2_mcspi_set_master_mode(struct spi_master *master)
{
	struct omap2_mcspi	*mcspi = spi_master_get_devdata(master);
	struct omap2_mcspi_regs	*ctx = &mcspi->ctx;
	u32 l;
	u32 intdly_msk = 0xFFFFFF8F;

	/*
	 * Setup when switching from (reset default) slave mode
	 * to single-channel master mode
	 */
	l = mcspi_read_reg(master, OMAP2_MCSPI_MODULCTRL);
	l &= ~(OMAP2_MCSPI_MODULCTRL_STEST | OMAP2_MCSPI_MODULCTRL_MS);
	l |= OMAP2_MCSPI_MODULCTRL_SINGLE;
	l &= intdly_msk; // INITDLY (Remove pause of SPI)
	mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, l);

	ctx->modulctrl = l;
}

That way I am setting INITDLY, but whenever I re-compile the kernel nothing happens. The SPI driver keeps working as if nothing happened!

  • Hi Luis,

    The intdly_msk value seems correct 0xFFFFFF8F but I would like to note the description of INITDLY field - This register is an option only available in SINGLE master mode, The controller waits for a delay to transmit the first SPI word after channel enabled and corresponding TX register filled. This delay is based on SPI output frequency clock, No clock output provided to the boundary and chip select is not active in 4 pin mode.
    If the conditions above are done but the issues still appears you should keep in mind the userspace processes are not really real time. Therefor I suggest you to try Processor SDK Linux-RT release and compare the results.

    BR
    Tsvetolin Shulev
  • It doesn't really seems to be a problem of not having a real time operating system though. I increased the word length to 32 bits and it improved a little bit. However, it's currently at 19.67mbps @ 48MHz. That's more than half of its maximum theoretical bandwidth that's going to waste! Do you have any idea why is that?