DMA & speed of spidev

I’m playing around with the SPI on my iMX7D module.

For that I changed the device tree as mentioned in this guide. I’m able to configure the interface with calls of ioctl() and and can send data out with write().

But I’m not happy with the transfer rate und I have two questions for that:

The datasheet says that a frequency of 52 MHz is possible. I add the following line to the device in the device tree:

spidev0: spidev@0 {
+   spi-max-frequency = <52000000>;
	status = "okay";
};

But the max achivable frequency that I can measure is 30 MHz. How can the frequency be raised?

And second: Between every transmitted FIFO-frame (32 bit x 64) I have a pause of 39 us. Therefore my transmission is slowed down significantly. How can I enable DMA support for the spidev? For me, it seems that it isn’t enabled by default in the device tree that is provided by Toradex for this module.

Best regards,
Mowlwurf

Hi @Mowlwurf

Thanks for writing to the Toradex Community.

I am sorry for the delayed answer.
Your issue of DMA might be related to the topic discussed in this answer.

Regarding setting the SPI clock frequency to 52 MHz, I will check and come back soon to you.

Best regards,
Jaski

Thank you for the link. The explanation for the behavior sound plausibel.

I already set the spi frame size to 32 bit. When I send 512 bytes of data I get a gap between the two FIFO blocks of around 35…40 µs.

In the link you posted it is mentioned that “request a multiple of 32 FIFO words for DMA to be used, other lengths will be worked on in interrupt mode”.

Now when I reduce my data by one word (4 Bytes) and therefore not send a multiple of 32 FIFO words I expected that the gap will be longer because the interrupt mode should be used. But it remains the same.

Do I don’t understand correctly the quoted sentence? How can I check for sure whether DMA is used or not?

hi @Mowlwurf

We are working on this issue an will come back soon to you.
Thanks for your patience.

Best regards,
Jaski

Dear @Mowlwurf,

We are able to reproduce the issue. I am trying to test with latest 3.0B2. Could you wait for a few more days, let me get back to you soon.

Dear @Mowlwurf,

Thank you for your patience. I have tested with 4.14.117 kernel with 3.0B2 image, there are quite some improvements in SPI driver and it is really using SPI DMA.

512 bytes with 32 bits per word mode has been transferred by 4 packets of the transaction, each 128 bytes packet. There is a 6.9us pause between the packet transactions. This is better than 40us pause between transaction with 2.8B6 image kernel.

Could you test the same with the 3.0B2 image and let us know is that meeting your requirement.

If you are not happy with 7us pause then try this suggestion, it does the continuous transfer without any pause. However, you need to live with the ERR009165 silicon issue.

Please refer this forum question : https://www.toradex.com/community/questions/2034/can-colibri-imx6-spi-ports-operate-at-up-to-52-mbp.html for SPI max frequency query. This is applicable to i.MX7 also, confirmed from NXP forum question.
Refer i.MX7D datasheet section 4.10.1.1 ECSPI Master mode timing for timing details.

Please let us know if you have any other queries.

Thank you very for your answer and that you could find a solution.

Here is a short test program:

#include <unistd.h>		// write
#include <fcntl.h>		// open
#include <sys/ioctl.h>	// ioctl
#include <linux/spi/spidev.h>
#include <cstdio>

#define SPI_DEVADDR			"/dev/spidev2.0"

int main(int argc, char *argv[])
{
	int spidev_fd;
	unsigned char spi_mode = SPI_MODE_0;	// Mode
	unsigned char spi_bpw = 32;				// Bits per Word
	unsigned long spi_speed = 52 * 1000 * 1000;	// Speed [Hz]

	if ((spidev_fd = open(SPI_DEVADDR, O_RDWR)) >= 0)
	{
		// set mode
		if (ioctl(spidev_fd, SPI_IOC_WR_MODE, &spi_mode) < 0)
		{
			perror("SPI set mode");
		}
		// set number of bits per word
		else if (ioctl(spidev_fd, SPI_IOC_WR_BITS_PER_WORD, &spi_bpw) < 0)
		{
			perror("SPI set bits per word");
		}
		// set max speed (in Hz)
		else if (ioctl(spidev_fd, SPI_IOC_WR_MAX_SPEED_HZ, &spi_speed) < 0)
		{
			perror("SPI set speed");
		}
		// send data
		else
		{
			unsigned char buf[16 * 256];
			if (write(spidev_fd, buf, sizeof(buf)) < 0)
				perror("SPI write");
		}

		close(spidev_fd);
	}
	else perror("SPI open");
}

I tried to run it with the 3.0B2 image but I got the following errors:

[ 2014.161978] imx-sdma 30bd0000.sdma: sdma firmware not ready!
[ 2014.167668] spidev spi2.0: SPI transfer failed: -22
[ 2014.172657] spi_master spi2: failed to transfer one message from queue
SPI write: Invalid argument

For the SPI max frequency:
I already changed the device tree by setting the max frequency to 52 MHz and I’m sending data only by using the write() command. But I still don’t get above 30 MHz.

Dear @Mowlwurf,

Did you use 3.0B2 image or did you build 4.14.117 kernel and updated on the module?
Did you update kernel, modules and device tree on the module?
Could you share a complete dmesg log file with us?

I didn’t get such an error with a 3.0B2 image.

In the official 3.0B2 image the spidev is not present in ‘/dev’.

Therefore I bitbake the ‘console-tdx-image’ of the BSP3.0b2 with the following addings in the device tree file ‘imx7d-colibri-emmc-eval-v3.dts’ to enable the spidev:

&ecspi3 {
	status = "okay";

	mcp2515: can@0 {
		status = "disabled";
	};

	spidev0: spidev@0 {
		spi-max-frequency = <52000000>;
		status = "okay";
	};
};

Thanks for your Input. Is spidev working as you want or do you still have issues?

The issue is still present.

With the BSP3.0b2 I get the error that the sdma firmware is not ready. With BSP2.8b6 I don’t have this problem.

Hello Raja,

sorry for replying very late but I was busy with another project the last weeks.

I tried what you suggested and replaced the device tree in the boot partition and it worked. I didn’t see the error anymore.

I will now make a clean build of the console-tdx-image including the modified device tree.

Dear @Mowlwurf,

We are not seeing this error with our 3.0B2 image. Maybe you need to clean build and probably SDMA is changed to as module driver. Maybe the modules section not updated correctly.

I would like to request you to do Flash our 3.0B2 image through TEZI and just overwrite the 'imx7d-colibri-emmc-biteval-v3.dtb which you built by bitbake on the boot partition. Boot partition can be accessed easily from the development PC by following this : https://www.toradex.com/community/questions/27787/ums-not-working-in-colibri-imx7-1gb.html

Please let us know if you still seeing this error with our standard release image with just device-tree modification.

The error is still present when I make a clean build of the console-tdx-image with the modified device tree.

When I use the same device tree with the official 3.0B2 image then the error don’t occure.

Therefore the cause must be in the build process. Do I have to modify the kernel or is there a module I have to load before I can use the SPI?

Best regards

Hi @Mowlwurf

Are you sure, that you get the exact same image and devicetree as Bsp 3.0b2 when you do a clean OE Build?
Additionally is your compiled custom devicetree is the same when you do a clean build?

How did you introduce your changes to the OE Build.

Best regards,
Jaski

These are the steps I take that produce the error:

Initalize the build environment:

$ mkdir ~/oe-coreV3.0
$ cd ~/oe-coreV3.0
$ repo init -u http://git.toradex.com/toradex-bsp-platform.git -b LinuxImage3.0 -m default.xml
$ repo sync
$ . export`

Add custom layer (link)

Build the image (exact copy of console-tdx-image)

$ bitbake console-tdx-image-gemac

Flash the image with the Easy Installer

Reboot the board (logfile, please have a look at timestamp 0.205224: sdma firmware isn’t found)

Load and execute the SPI test program I posted in the comment of Oct 21

It looks like the issue is more on building devicetree using Yocto. Could you ask a new Question, please? Thanks.

Please look here: https://www.toradex.com/community/questions/45890/spidev-on-bsp30b2.html

Yeah sure.

Thanks.