SPI byte ordering

Hi,

I receive SPI data from a remote processor which acts as the SPI slave. Per this thread, I’ve set the SPI transfer word length to 32 bits, to minimise the loss in transfer rate incurred by the momentary pause between word transfers. If I use a word length of 8 bits, the following issue doesn’t occur, but the total throughput of the interface is reduced due to the ~1us delay between each 8 bit transfer.

The remote processor packs a buffer with data, which is sent out on the MISO line via DMA. I have verified the byte ordering of this data to be correct with an oscilloscope. An example of this SPI slave data is as follows:

0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11

The data is received into an unsigned char buffer, and while the data is correct, the byte ordering is not. It appears that each of the 32-bit words has been processed as 4 SPI slave uint8_t integers in reverse order. As such, the receiving buffer looks like this:

3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8

I can correct the byte ordering in software, but I was wondering whether there was a hardware method for correcting the SPI reordering. I’ve tried using the SPI_LSB_FIRST flag when setting up the SPI interface, as well as explicitly setting SPI_IOC_RD_LSB_FIRST and SPI_IOC_WR_LSB_FIRST in ioctl(), but these don’t have any effect.

Is there a way to correct this in hardware, or is the only option to address the incorrect ordering in software?

Thanks!

If I could also ask a secondary question. I’m finding that I can reorder the bytes in software up to 40Mhz. At 50Mhz or 60Mhz, the byte order doesn’t follow the above sequence. Is it possible that the transfer of data above 40Mhz into the RX buffer (as specified as part of the spi_ioc_transfer struct) isn’t fast enough, cause the data to be jumbled? The data values themselves are correct, but the order in which they appear in the RX buffer is completely wrong.

HI @jars121

Thanks for writing to the Toradex Community!

Could you share a sample code which transforms 8-bit data to 32-bit words?

Best regards,
Jaski

Could you share some error log? What is your SPI communication speed?

Hi @jaski.tx

Thanks for your support. I’ve actually addressed the byte ordering issue by packaging the data into the DMA buffer on the remote processor in reversed 32-bit order, so that the data is received/parsed correctly by the Apalis. This has been working well, as there’s no software reordering required on the Apalis.

As for the communication speed, the interface appears to be working at speeds up to 40MHz. Beyond 40MHz, the data is no longer correct. I had previously thought the data was correct but jumbled, but I’ve just done some further testing and the data is definitely incorrect. The remote processor can handle up to 50MHz, and I’ve modified the device tree of the Apalis to support up to 60MHz, so I’m not sure why 40MHz is the perceived limit. 40MHz might be enough for my particular requirements, but if there’s anything you can think of for me to check it’d be appreciated.

You are welcome.

As for the communication speed, the interface appears to be working at speeds up to 40MHz. Beyond 40MHz, the data is no longer correct. I had previously thought the data was correct but jumbled, but I’ve just done some further testing and the data is definitely incorrect.

So this means the data sent between the remote processor and Apalis is wrong?
Did you check this using an oscilloscope?
Which SPI Interface (PINS) are you using exactly?
Could you share your devicetree settings?

Thanks and best regards,
Jaski

My apologies for the delay in getting back to @jaski.tx my attention has been elsewhere on the project.

In answer to your first question: yes, the data received by the Apalis is incorrect. The data in the SPI DMA TX buffer on the remote processor does not equal the SPI RX data on the Apalis. I will confirm this with the oscilloscope in the morning.

As for the Apalis SPI pins, I’m using LPSPI2 (MISO pin 229, MOSI pin 231, CS pin 233 and CLK pin 235). The relevant device tree sections are shown below:

&iomuxc {
    apalis-imx8qm {
        pinctrl_lpspi2: lpspi2grp {
            fsl,pins = <
                IMX8QM_SPI2_SCK_DMA_SPI2_SCK                            0x0600004c
                IMX8QM_SPI2_SDO_DMA_SPI2_SDO                            0x0600004c
                IMX8QM_SPI2_SDI_DMA_SPI2_SDI                                0x0600004c
                IMX8QM_SPI2_CS0_LSIO_GPIO3_IO10                          0x0600004c
            >;
        };
    };
};

&lpspi2 {
    status = "okay";
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_lpspi2>;
    #address-cells = <1>;
    #size-cells = <0>;
    cs-gpios = <&lsio_gpio3 10 GPIO_ACTIVE_LOW>;
    assigned-clock-rates = <128000000>;

    spidev1: spi@0 {
        compatible = "toradex,evalspi";
        reg = <0>;
        spi-max-frequency = <60000000>;
    };
};

Just to clarify my earlier issue. I’m actually finding that the data received is incorrect for any frequency above 30MHz, not 40MHz as previously stated. Up to 30MHz works as expected, but as soon as a frequency of 31MHz or higher is selected, the received data is no longer correct. As stated above, the remote processor is capable of upwards of 50MHz, which has been tested successfully using other SPI interfaces on the remote processor.

I’m approaching limit of the current 30MHz bandwidth for my application, so being able to operate the SPI at closer to 50MHz is required. Any guidance would be very much appreciated as always.

A bit of an update on my previous comment.

I’ve since done some additional testing, and have found a few interesting things. Firstly, I’m now able to set (via the spidev driver) an SPI frequency of up to 40MHz. The actual frequency (as measured on an oscilloscope) is ~38MHz. This 38MHz ‘real’ frequency is observed for spidev driver speed_hz values of 30MHz to 40MHz.

Per this post, I had set the assigned-clock-rates device tree value to 128MHz (as shown above), however when checking the kernel clock configuration via cat /sys/kernel/debug/clk/clk_summary | grep spi2 I get the following:

root@apalis-imx8:~# cat /sys/kernel/debug/clk/clk_summary | grep spi2
     spi2_clk                     0            0            0            120000000            0            0            5000
        spi2_lpcg_clk             0            0            0            120000000            0            0            5000
        spi2_lpcg_ipg_clk         0            0            0            120000000            0            0            5000

I was expecting the listed frequencies to be 128MHZ (as per the device tree and the above referenced post) as opposed to the 120MHz shown. I’m not sure if this is relevant/useful information or not, but I thought I’d point it out.

This post outlines the two-stage divider used by the SPI subsystem. Applying this logic to either the 128MHz or 120MHz source clock, I’m not sure how the resultant ‘real’ SPI frequency is ~38MHz. At this stage I’m aiming to achieve a ‘real’ SPI frequency as close to 50MHz as possible (the limit of the remote processor). This may be the ~38MHz frequency I’m observing, but as I can’t make sense of this value I’d like to make absolutely certain that a frequency closer to 50MHz definitely isn’t possible.

Hi

These are good news, that you did some progress. Could you provide the version of the software of your module thus I can try to reproduce the issue on my side?

Thanks and best regards,
Jaski

Hi Jaski,

I’m using linux-toradex_5.4-2.3.x (with u-boot-toradex_2020.04).

Thanks!

Hi,
Thanks for this information. I will try to reproduce the error. Meanwhile could you also have a look here? This thread is about iMX8X, but it may help you.

Best regards,
Jaski