How to use SPI on Colibri VF61 in Linux

Dear Guys,

I use the VF61 and I’m starting to write a simple code that read some sensors and I want to use the SPI.

I compiled the image in order to use the SPI using the following link:

I compiled the example spidev_test.c and it’s working on my new image, in the mean there are no errors ,
this test runs with the output RX zero (but I don’t have the right sensor)

Now I want to associate the following PIN to my sensors using SPI.

PIN 21 → differential pressure sensor chip select
PIN 23 → absolute pressure sensor chip select
PIN 25 → air flow temperature sensor chip select

What should I do?

If I understand rightly I need to configure the Device Tree to include my PIN but I don’t kown what I do it.
Could you help me?
Are any examples to configure the SPI and the PIN please?
Thank you

Which Linux branch did you use to compile your image?

Please check lines 92-102 and 182-196 of vf-colibri-aster.dtsi « dts « boot « arm « arch - linux-toradex.git - Linux kernel for Apalis, Colibri and Verdin modules

Dear @alex.tx,
Thank you for your answer.
I used the branch toradex_vf_4.4.

If I understood I need to modify those lines with my SODIMM:

&iomuxc {
        vf610-colibri {
                pinctrl_gpiokeys: gpiokeys {
                        fsl,pins = <
                                VF610_PAD_PTB19__GPIO_41        0x218d
                        >;
                };

                pinctrl_aster_dspi1: dspi1grp {
                       fsl,pins = <
                            VF610_PAD_PTD6__DSPI1_SIN               0x33e1
                            VF610_PAD_PTD7__DSPI1_SOUT              0x33e2
                            VF610_PAD_PTD8__DSPI1_SCK               0x33e2
                    >;
            };

            pinctrl_aster_spi_gpio: spigpios {
                    fsl,pins = <
                            /* CS0 */
                          /*  VF610_PAD_PTD5__GPIO_84                 0x22ed*/
                          /* **To configure the PIN 23** */
                               VF610_PDA_PTA20_GPIO_23                0x22ed   
                            /* CS1 */
                           // VF610_PAD_PTB18__GPIO_40                0x22ed
                           /* **To configure the PIN 21** */
                               VF610_PDA_PTB4_GPIO_21                0x22ed   
                           /* CS2 */
                            /* **To configure the PIN 25** */
                               VF610_PDA_PTB13_GPIO_25                0x22ed  
                              
                    >;
            };
    };
};

Is it right, please?
In the code spidev_test.c If I want Read the value of sensor CS1 I need to change the device=“/dev/spidev1.1” and CS2 → device =“dev/spidev1.2”

In the file vf-colibri-eval-v3.dtsi I need to add the following lines:

/* Colibri SPI */
&dspi1 {
        status = "okay";

    mcp2515can: can@0 {
            compatible = "microchip,mcp2515";
            reg = <0>;
            clocks = <&clk16m>;
            /* pinctrl is set in iomuxc from hoggrp-0 */
            interrupt-parent = <&gpio1>;
            interrupts = <11 GPIO_ACTIVE_LOW>;
            spi-max-frequency = <10000000>;
            status = "disabled";

    };

    spidev0: spidev@0 {
            compatible = "toradex,evalspi";
            reg = <0>;
            spi-max-frequency = <50000000>;
            status = "okay";
    };

    spidev1: spidev@1 {
                compatible = "toradex,evalspi";
                reg = <0>;
                spi-max-frequency = <50000000>;
                status = "okay";
    };

    spidev2: spidev@2 {
                compatible = "toradex,evalspi";
                reg = <0>;
                spi-max-frequency = <50000000>;
                status = "okay";
        };
    };

Thank you for your support.
Best regards
Matteo

Hi @Matte

Were you able to compile the device-tree?
Could you share the demsg.log in a text file?

Thanks and best regards,
Jaski

Dear @jaski.tx,
I don’t insert the previous lines in the tree because I don’t understand if those lines are right?
Could you tell me if the previous lines are right?
I can share the build.log link text (it’s the only log I found in my folder) generated when I enabled the spi and disable mcp2515can.
Thank you

Dear Matteo,

Unfortunately these lines are not correct. This device-tree files won’t compile. I think you should start over: I imagine you are using the Colibri Evaluation Carrier Board and with Pin number you mean the SODIMM Pins. So first of all you should not mix the device-tree files and nodes.

For SODIMM 23 as Chipselect, you should do the following changes:

diff --git a/arch/arm/boot/dts/vf-colibri-eval-v3.dtsi b/arch/arm/boot/dts/vf-colibri-eval-v3.dtsi
index 356ad251e2ed..e1ea9040e291 100644
--- a/arch/arm/boot/dts/vf-colibri-eval-v3.dtsi
+++ b/arch/arm/boot/dts/vf-colibri-eval-v3.dtsi
@@ -107,14 +107,14 @@
                interrupt-parent = <&gpio1>;
                interrupts = <11 GPIO_ACTIVE_LOW>;
                spi-max-frequency = <10000000>;
-               status = "okay";
+               status = "disabled";
        };
 
        spidev0: spidev@0 {
                compatible = "toradex,evalspi";
                reg = <0>;
                spi-max-frequency = <50000000>;
-               status = "disabled";
+               status = "okay";
        };
 };
 
diff --git a/arch/arm/boot/dts/vf-colibri.dtsi b/arch/arm/boot/dts/vf-colibri.dtsi
index cca8f38facb7..4df4376000b8 100644
--- a/arch/arm/boot/dts/vf-colibri.dtsi
+++ b/arch/arm/boot/dts/vf-colibri.dtsi
@@ -70,7 +70,7 @@
 &dspi1 {
        bus-num = <1>;
        pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_dspi1>;
+       pinctrl-0 = <&pinctrl_dspi1 &pinctrl_dspi1_gpios>;
 };
 
 &edma0 {
@@ -237,13 +237,17 @@
 
                pinctrl_dspi1: dspi1grp {
                        fsl,pins = <
-                               VF610_PAD_PTD5__DSPI1_CS0               0x33e2
                                VF610_PAD_PTD6__DSPI1_SIN               0x33e1
                                VF610_PAD_PTD7__DSPI1_SOUT              0x33e2
                                VF610_PAD_PTD8__DSPI1_SCK               0x33e2
                        >;
                };
 
+               pinctrl_dspi1_gpios:spigpios {
+                       fsl,pins = <
+                               VF610_PAD_PTA20__GPIO_10                0x33e2 /*SODIMM 23*/
+                       >;
+               };
                pinctrl_esdhc1: esdhc1grp {
                        fsl,pins = <
                                VF610_PAD_PTA24__ESDHC1_CLK     0x31ef

For the SODIMM Pins, 23 and 25 you should do the changes accordingly and check if this works. I just compiled the devicetree and it compiled without any errors.

Best regards,
Jaski

Hi @Matte

  1. In your reply, you say that …

You are right, it is SODIMM 23, I changed my reply above.

  1. In the file vf-colibri-eval-v3.dtsi I need to define also spidev1 (reg) and spidev2 (reg) similar to spidev0 in order to use the 3 sensors?

Yes.

  1. I need to set on Toradex GPIO Tool these SODIMM with the Description GPIO or it’s not necessary.

No, this is not necessary.

Best regards,
Jaski

Dear @jaski.tx,
thank you for your answer, now I understand.
Yes, I use Colibri Evaluation Carrier Board and Pin number is the SODIMM Pin.
I have some easy questions for you:

  1. In your reply, you say that
    VF610_PAD_PTA20__GPIO_10 is /SODIMM 21/

if I’m not wrong SODIMM 21 is VF610_PAD_PTB4__GPIO_26 and SODIMM 23 is
VF610_PAD_PTA20__GPIO_10 .

  1. In the file vf-colibri-eval-v3.dtsi I need to define also spidev1 (reg<1>) and spidev2 (reg<2>) similar to spidev0 in order to use the 3 sensors?

  2. I need to set on Toradex GPIO Tool these SODIMM with the Description GPIO or it’s not necessary.

Thank you
Best regards
Matteo

Dear @jaski.tx ,
thank you for your informations.
I compile the tree and it seems right to me.
Now I try to read my sensors.
best regards
Matte

You are welcome. Let us know your results.

Best regards,
Jaski

Deat @jaski.tx,

I built the image and uploaded it on my VF61 using the following commands:

On PC in linux-toradex:

make colibri_vf_defconfig
make -j3 zImage | tee build.log
make vf610-colibri-eval-v3.dtb

The build is right.
Then I copied the zImage and vf610-colibri-eval.dtb in SD_CARD\colibri_vf\

On the VF61 I did:
nand erase.part ubi
run setupdate
run update

The new Image is uploaded.
Now I have three devices /dev/spidev1.0, /dev/spidev1.1 and /dev/spidev1.2 on my VF61.

Could you tell me if I forgot any steps?

I don’t understand if the my sensors are working, because I wrote a my C++ code, my code is similar to Arduino code that is working perfectly but the results are different.

Do you have any suggestions?
Best regards
Matteo

Hi Matteo

The new Image is uploaded. Now I have three devices /dev/spidev1.0, /dev/spidev1.1 and /dev/spidev1.2 on my VF61.

That looks good.

Could you tell me if I forgot any steps?
No

I don’t understand if the my sensors are working, because I wrote a my C++ code, my code is similar to Arduino code that is working perfectly but the results are different.

What exactly is the difference? Could you share some comparison’s values?

Best regards,
Jaski

HI @Matte

Thanks for sharing the code, but I think it will be easier to use an oscilloscope to check the difference between the values are sent by the sensor and the values are received by the software.

Best regards,
Jaski

Dear @jaski.tx,
thank you very much for your support.

On the Arduino the result are:

  byte[0] 10  byte[1] 200 the pressure value is 1,01325 atm 

On the VF61 I obtain

byte[0] 8 byte[1] 17 the pressure is about 0,2368616 atm

The Arduino code is

MySensor sensor();

void setup() {
  Serial.begin(115200); // start Serial communication
  SPI.begin(); // start SPI communication
  sensor.begin(); // run sensor initialization
}

void loop() {
  // the sensor returns 0 when new data is ready
  sensor.readSensor();
  delay( 100 ); // Slow down sampling to 10 Hz. This is just a test.
}

where

void init()
{
   _spi_settings = SPISettings(800000, MSBFIRST, SPI_MODE0);
    pinMode(_SS_PIN, OUTPUT);  // set PIN --> output
    digitalWrite(_SS_PIN, HIGH);   //set PIN --> 1
}

uint8_t readSensor()
{
    uint8_t count = 4; // transfer 4 bytes (the last two are only used by some sensors)
    memset(_buf, 0x00, count); // probably not necessary, sensor is half-duplex
    SPI.beginTransaction(_spi_settings);
    digitalWrite(_SS_PIN, LOW); // set PIN 0
    SPI.transfer(_buf, count);
    digitalWrite(_SS_PIN, HIGH); // set PIN 1
    SPI.endTransaction();
 }

My Code is:

int main(int argc, char *argv[])
{
    int ret =0;
    PressureSensor absolutePressure = PressureSensor();
    sleep(0.5);
    absolutePressure.Init();
    sleep(0.5);
    for(int i=0; i< 100; i++)
    {
    	absolutePressure.ReadSensor();
    	sleep(0.5);
    }

    absolutePressure.Close();
    return ret;
}
/* Constructor*/
PressureSensor::PressureSensor() :
	_fd(-1),  // int _fd;
	_mode(SPI_MODE_0),
	_speed(800000),
	_device("/dev/spidev1.1"),
	{
	std::cout<<" fd "<< _fd<< " mode "<<_mode<<"\n"
			<<" speed "<< _speed<< "_device"<<"\n"
			<< _device <<"\n";
	}

/*Init */
void PressureSensor::Init()
{
	int ret = 0;
	int msb =0;
	int bits =8;
        _fd = open(_device, O_RDONLY);
	if (_fd < 0)
		pabort("can't open device");

	ret = ioctl(_fd, SPI_IOC_RD_MODE32, &_mode);
	if (ret == -1)
		pabort("can't get spi mode");

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

	ret = ioctl(_fd, SPI_IOC_RD_LSB_FIRST, &msb);
		if (ret == -1)
			pabort("can't set MSB per word");

	ret = ioctl(_fd, 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);
}

/* ReadSensor */
uint8_t PressureSensor::ReadSensor()
{
	uint8_t count = 4; // transfer 4 bytes (the last two are only used by some sensors)
	memset(_buf, 0x00, count); // probably not necessary, sensor is half-duplex
	
	struct spi_ioc_transfer tr;
	tr.rx_buf =(unsigned long)_buf;   // where _ uint8_t _buf[4];   
        tr.len = 4;
	tr.delay_usecs = 200;
	tr.speed_hz = _speed;
	tr.bits_per_word = 8;

	int ret = ioctl(_fd,  SPI_IOC_MESSAGE(1), &tr);
	if (ret == -1)
		pabort("can't send spi message");
	else {
	  printf("Device Value: %d %d - %d - %d\n",_buf[0], _buf[1], _buf[2], _buf[3]);
	  // if device is normal and there is new data, bitmask and save the raw data
	}
	return _status;
}

I think that the 2 codes are equivalent, or am I wrong?
Best regards

Hi @jaski.tx,
thank you for your suggestion-
next week I’ll return to office and I’ll check the values with the oscilloscope.
The only difference between the Arduino code and my Toradex code
is that in the Arduino I need to set the PIN as OUTPUT and High and low before and after the transfer data.
In the toradex this step is not done.
Do you confirm me that it is not necessary?
Thank you
Best regards
Matteo

You are welcome. Please let us know your results once you have done tests with oscilloscope.

The only difference between the Arduino code and my Toradex code is that in the Arduino I need to set the PIN as OUTPUT and High and low before and after the transfer data.

I don’t know what do you mean exactly. On Colibri VF61, you define the pins with their functions in device-tree and you do the transfer in your code. Nothing more is needed.

Best regards,
Jaski