Apalis iMX8 SPI multiple chip select

Hello,

Trying to enable two chip selects for SPI1 with GPIO6_19 and GPIO6_20. The SPI node on device tree looks like this (fsl-imx8qm-apalis.dts)

/* Apalis SPI1 */
&lpspi0 {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_lpspi0 >;
	num-cs = <2>;
	fsl,espi-num-chipselects = <2>;
	cs-gpios =<&gpio6 19 GPIO_ACTIVE_LOW>,
		  <&gpio6 20 GPIO_ACTIVE_LOW>;
	#address-cells = <1>;
	#size-cells = <0>;
	status = "okay";
	clock-frequency= <40000000>;
	spidev0: spi@0 {
		compatible = "toradex,evalspi";
		reg = <0>;
		spi-max-frequency = <20000000>;
	};

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

};

muxing:

		/* Apalis SPI1 */
		pinctrl_lpspi0: lpspi0grp {
			fsl,pins = <
				SC_P_SPI0_SCK_DMA_SPI0_SCK		0x0600004c
				SC_P_SPI0_SDO_DMA_SPI0_SDO		0x0600004c
				SC_P_SPI0_SDI_DMA_SPI0_SDI		0x0600004c
				SC_P_ENET1_RGMII_RXD1_LSIO_GPIO6_IO19	0x0600004c
				SC_P_ENET1_RGMII_RXD2_LSIO_GPIO6_IO20   0x0600004c
			>;
		};

Linux dev:

root@apalis-imx8:~# ls /dev |grep spidev
spidev0.0
spidev0.1
spidev1.0

SPI C code:

   #define SPI_CLK_SPEED 20 * 1000000 //10Mhz
    #define SPI_BITS 8
    #define SPI_DELAY 0
    static const char *device = "/dev/spidev0.0";
    static const char *device01 = "/dev/spidev0.1";
    struct spi_ioc_transfer tr;
    struct spi_ioc_transfer tr01;
    int fd_spi,fd_spi01;
    
    uint8_t default_tx[] = {
    	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    	0x40, 0x00, 0x00, 0x00, 0x00, 0x95,
    	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    	0xF0, 0x0D,
    };
    
    uint8_t default_rx[ARRAY_SIZE(default_tx)] = {0, };
    
    void transfer(int fd,struct spi_ioc_transfer* tr, uint8_t const *tx, uint8_t const *rx, size_t len)
    {
    	int ret;
    	tr->tx_buf = (unsigned long)tx;
    	tr->rx_buf = (unsigned long)rx;
    	tr->len = len;
    
    
    	ret = ioctl(fd, SPI_IOC_MESSAGE(1), tr);
    	if (ret < 1)
    	{
    		pabort("can't send spi message");
    		exit(1);
    	}
    
    }
    
    int SPI_init( const char  *dev,struct spi_ioc_transfer *tr,uint32_t mode,uint8_t bits,uint32_t speed,uint16_t delay)
    {
    	int spiFD,ret;
    
    	tr->delay_usecs = delay;
    	tr->speed_hz = speed;
    	tr->bits_per_word = bits;
    
    
    	if (mode & SPI_TX_QUAD)
    		tr->tx_nbits = 4;
    	else if (mode & SPI_TX_DUAL)
    		tr->tx_nbits = 2;
    	if (mode & SPI_RX_QUAD)
    		tr->rx_nbits = 4;
    	else if (mode & SPI_RX_DUAL)
    		tr->rx_nbits = 2;
    	if (!(mode & SPI_LOOP)) {
    		if (mode & (SPI_TX_QUAD | SPI_TX_DUAL))
    			tr->rx_buf = 0;
    		else if (mode & (SPI_RX_QUAD | SPI_RX_DUAL))
    			tr->tx_buf = 0;
    	}
    
    	spiFD = open(dev, O_RDWR);
    	if (spiFD < 0)
    		pabort("can't open device");
    
    
    	 // spi mode
    	ret = ioctl(spiFD, SPI_IOC_WR_MODE32, &mode);
    	if (ret == -1)
    		pabort("can't set spi mode");
    
    	ret = ioctl(spiFD, SPI_IOC_RD_MODE32, &mode);
    	if (ret == -1)
    		pabort("can't get spi mode");
    
    
    	 //bits per word
    	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
    	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");
    
    	printf("spi mode: 0x%x\n", mode);
    	printf("bits per word: %d\n", bits);
    	printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000);
    	return (spiFD);
    
    }
    
    int main()
    {
    	 fd_spi = SPI_init(device,&tr,SPI_MODE,SPI_BITS,SPI_CLK_SPEED,SPI_DELAY);
    	 fd_spi01 = SPI_init(device01,&tr01,SPI_MODE,SPI_BITS,SPI_CLK_SPEED,SPI_DELAY);
    
    	 while(1)
    	 {
    		//transfer value:
    		   usleep(2000);
    		   transfer(fd_spi,&tr, default_tx, default_rx, 5); // (was &rx instead of str) 1 byte
    		   usleep(2000);
    		   transfer(fd_spi01,&tr01, default_tx, default_rx, 5);
    	 }
    }

The result on oscilloscope: only one of the chip selects is working with a big delay (dmesg.log is in attachements)dmesg.log. (In addition the native chip select goes low with every byte sent.)
Oscilloscope images:
[upload|1t5z4IdE4MLycrgtfUDWfd+Elt0=]
zoom in:
[upload|GXBbDw0sl8tl2csq40mE6g7Gzu0=]
linux version: Linux apalis-imx8 4.14.117
is there something I should change in the device tree?.

Best regards,
Majd

Hi @majd.m

Thanks for writing to the Toradex Community!

Could you provide the version of the software of your module?

Please share the dmesg log, sample code for sending data on SPI Bus and the oscilloscope image?

Thanks and best regards,
Jaski

Hi @jaski.tx,
thanks for your feedback. I have updated the post with the requested information

Best regards,
Majd

Hi @majd.m

Thanks for your Input. I will try to reproduce this issue and come soon back to you.

Best regards,
Jaski

Hi, is there any update? Thank you

Best regards, Majd

Hi @majd.m

Yes, we can reproduce the issue. We are looking for the root cause of this issue. Once we have more Information, we will come back to you.

Best regards,
Jaski

A fix for this has been merged here:

http://git.toradex.com/cgit/linux-toradex.git/commit/?h=toradex_4.14-2.0.x-imx-next&id=1273072dc60c0fdf6f0c63af4237c329c0f72742

Hi @marcel.tx,

Thank you for your support. I updated the kernel to this commit and compiled it, then transfered the kernel (“Image” file) and the device tree for apalis board “fsl-imx8qm-apalis-eval.dtb” to the boot partition. First the module doesnt boot, because it searchs for “fsl-imx8qm-apalis.dtb” and cant find it. By changing the device tree to this name name. the kernel starts to boot but it gets kernel panic after it (with default device tree definitions)

When I use the old compiled device tree file the kernel boots, but i want to make some changes on the device tree.

Best regards, Majd

HI @majd.m

You should flash the latest nightly build ( Activate CI Feeds in Toradex Easy Installer ) and then do a custom kernel with the patch. This should work.

Best regards,
Jaski

Hi @jaski.tx,

Thanks, I have done some workaround method and made it work. I tested 3 chip selects on SPI0 and seem to work, but the only remaining issue is the chip select speed.

There is a latency of about 35µs between selecting the chip and SPI transfer as well as after SPI transfer. Is it not possible to reduce this latency?

1944-3spl.png

Thanks and Best regards,Majd

HI @majd.m

Perfect the Gpio Chip selects are working. Thanks for your feedback.

For the delay could ask a new question, please?

Best regards,
Jaski