RPI_333333
Posts: 13
Joined: Wed Nov 14, 2018 8:53 am

Using SPI on python

Mon Dec 03, 2018 1:27 pm

Hi
I have an SPI device that connected to my RPI 3 via SPI.
I installed and enabled SPI.
I have a sample code to test the connection between the RPI to the device and it worked fine.
The code read the value of register at address 0x4000 and print it.
The code is in C and uses wiring pi libary and BCM2835 libary.

I want to do the same thing in python with spidev but didn't succeeded
here's the code:

Code: Select all

import spidev
spi=spidev.SpiDev()
spi.open(0,1)
response=spi.xfer2([0x40,0x00])
print('Result is: ' , response)
spi.close()
This is the result i get: Result is : [0,0]

I don't understand why i get all zeros (The result should be 0x3011 as i get in the C code)

Any help would be appreciated

DirkS
Posts: 9617
Joined: Tue Jun 19, 2012 9:46 pm
Location: Essex, UK

Re: Using SPI on python

Mon Dec 03, 2018 3:52 pm

Are you sure you don't have to send something before you get a response?
What kind of device is it?

danjperron
Posts: 3141
Joined: Thu Dec 27, 2012 4:05 am
Location: Québec, Canada

Re: Using SPI on python

Mon Dec 03, 2018 5:32 pm

What is your device and could you also put your C code also. We need to compare what you did.

RPI_333333
Posts: 13
Joined: Wed Nov 14, 2018 8:53 am

Re: Using SPI on python

Tue Dec 04, 2018 7:19 am

danjperron wrote:
Mon Dec 03, 2018 5:32 pm
What is your device and could you also put your C code also. We need to compare what you did.
Thank you for your answer,
The device is an FPGA development board which i want to connect to my RPI3 via SPI.
I am trying to read one of the FPGA registers.

The goal: Reading FPGA register at address 0x4000 and print the result

Here is the C code:

Code: Select all


int main(void)
{
char SPI_address[]={0x40,0x00,0x00,0x00}


//Init SPI
if (!bcm2835_init())
  {
    printf("bcm2835_init failed \n");
    return 1;
  }
  printf("Init complete\n");

	bcm2835_spi_begin();
	bcm2835_spi_setDataMode(BCM2835_SPI_MODE0);
	bcm2835_spi_setClockDivider(BCM2835_SPI_CLOCK_DIVIDER_32);
	bcm2835_spi_chipSelect(BCM2835_SPI_CS0);
	bcm2835_spi_setChipSelectPolarity(BCM2835_SPI_CS0, LOW);
	bcm2835_spi_setBitOrder(BCM2835_SPI_BIT_ORDER_MSBFIRST);


//Setting cs
bcm2835_spi_chipSelect(BCM2835_SPI_CS0);
//Read register value
bcm2835_spi_transfern(&SPI_address[0], 4);

printf("Register values are: ");
for ( i=0; i<4; cnt++ )
 {
		printf("%02X ",SPI_address[i]);
}

}




Here is the C code outpot:
"
Register values are: FF FF 30 11
"

Here is the python code (i added init to the SPI paramaters):

Code: Select all

import spidev
spi=spidev.SpiDev()
spi.open(0,0)
spi.mode=0b00
spi.lsbfirst=False
spi.max_speed_hz=1350000

response=spi.xfer2([0x40,0x00,0x00,0x00])
print('Result is: ' , response)
spi.close()



Here is the Python code outpot:
"
Result is: [0,0,0,0]
"


Does bcm2835_spi_transfern is the same as spi.xfer2 ?

What is the difference between the bcm2835 libary and spidev (is there a ny difference?)

I am able to connect to the device in pyhon but recieve all zeros

Any help will be appriciated

User avatar
joan
Posts: 13655
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Using SPI on python

Tue Dec 04, 2018 9:38 am

I would run (my) piscope and compare what is going on with the C and the Python. That should make the difference (and hopefully the error) obvious.

http://abyz.me.uk/rpi/pigpio/piscope.html

(requires the pigpio daemon to be running, sudo pigpiod)

RPI_333333
Posts: 13
Joined: Wed Nov 14, 2018 8:53 am

Re: Using SPI on python

Tue Dec 04, 2018 11:17 am

joan wrote:
Tue Dec 04, 2018 9:38 am
I would run (my) piscope and compare what is going on with the C and the Python. That should make the difference (and hopefully the error) obvious.

http://abyz.me.uk/rpi/pigpio/piscope.html

(requires the pigpio daemon to be running, sudo pigpiod)
I tested both codes with piscope.
It seems that when i run my C code everything looks normal
When i run my pyhon code nothing happened (no clock, no CS)..

Any idea what actualy the problem here? why the python code doesn't work

User avatar
joan
Posts: 13655
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Using SPI on python

Tue Dec 04, 2018 12:21 pm

It looks like it should work to me.

I ran your Python code (changing the SPI speed to 50000 to make sure it could be captured by piscope).
Screenshot from 2018-12-04 12-18-11.png
Screenshot from 2018-12-04 12-18-11.png (50.83 KiB) Viewed 538 times

RPI_333333
Posts: 13
Joined: Wed Nov 14, 2018 8:53 am

Re: Using SPI on python

Tue Dec 04, 2018 12:53 pm

joan wrote:
Tue Dec 04, 2018 12:21 pm
It looks like it should work to me.

I ran your Python code (changing the SPI speed to 50000 to make sure it could be captured by piscope).

Screenshot from 2018-12-04 12-18-11.png
Maybe something is not installed correctly at my end ?
Could you explain how should i check?

when i run lsmod i get:

Image
Attachments
lsmod.PNG
lsmod.PNG (21.28 KiB) Viewed 523 times

danjperron
Posts: 3141
Joined: Thu Dec 27, 2012 4:05 am
Location: Québec, Canada

Re: Using SPI on python

Tue Dec 04, 2018 3:15 pm

the bcm2835 library uses direct access to the hardware.

Maybe you have something wrong with the device driver.


What is your /boot/config.txt ?
whats is the result of ls -l /dev/spi* ?
Which version of python are you using ? (python2 or python3) Did it fail on both python

Maybe try this version of C using IOCTL. If it works then it's not the device driver.

Code: Select all

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/spi/spidev.h>
#include <stdint.h>


int spi_handle=-1;
int spi_speed=1000000;


uint8_t spi_init(void) {
        int status_value = -1;
//        unsigned char spi_mode=SPI_MODE0|SPI_LSB_FIRST;
        unsigned char spi_mode=SPI_MODE_0;
        unsigned char spi_bitsPerWord=8;

        spi_handle = open("/dev/spidev0.0",O_RDWR);

       if(spi_handle < 0)
         {
           perror("Error - Could not open SPI device");
           exit(1);
         }


      status_value = ioctl(spi_handle, SPI_IOC_WR_MODE, &spi_mode);
      if(status_value < 0)
      {
        perror("Could not set SPIMode (WR)...ioctl fail");
        exit(1);
      }

      status_value = ioctl(spi_handle, SPI_IOC_RD_MODE, &spi_mode);
      if(status_value < 0)
      {
       perror("Could not set SPIMode (RD)...ioctl fail");
       exit(1);
      }

      status_value = ioctl(spi_handle, SPI_IOC_WR_BITS_PER_WORD, &spi_bitsPerWord);
      if(status_value < 0)
      {
      perror("Could not set SPI bitsPerWord (WR)...ioctl fail");
      exit(1);
      }

      status_value = ioctl(spi_handle, SPI_IOC_RD_BITS_PER_WORD, &spi_bitsPerWord);
      if(status_value < 0)
    {
      perror("Could not set SPI bitsPerWord(RD)...ioctl fail");
      exit(1);
    }

    status_value = ioctl(spi_handle, SPI_IOC_WR_MAX_SPEED_HZ, &spi_speed);
    if(status_value < 0)
    {
      perror("Could not set SPI speed (WR)...ioctl fail");
      exit(1);
    }

    status_value = ioctl(spi_handle, SPI_IOC_RD_MAX_SPEED_HZ, &spi_speed);
    if(status_value < 0)
    {
      perror("Could not set SPI speed (RD)...ioctl fail");
      exit(1);
    }
    return(1);
}




void spi_transfer(unsigned char *txbuff, unsigned char *rxbuff, int len)
{
  int ret;
  struct spi_ioc_transfer spi_tr = {
                .tx_buf = (unsigned long)  txbuff,
                .rx_buf = (unsigned long)  rxbuff,
                .len = len,
                .delay_usecs = 0,
                .speed_hz = spi_speed,  // speed in KHz to Hz
                .bits_per_word = 8,
              };
        ret = ioctl(spi_handle,SPI_IOC_MESSAGE(1), &spi_tr);
        if(ret < 1)
         {
          perror("Can't send spi message\n");
          close(spi_handle);
          exit(2);
        }
}




int main(void)
{
unsigned char SPI_TXM[]={0x40,0x00,0x00,0x00};
unsigned char SPI_RCV[4];


//Init SPI
if (!spi_init())
  {
    printf("IOCTL SPI failed \n");
    return 1;
  }
  printf("Init complete\n");


spi_transfer(SPI_TXM,SPI_RCV, 4);

printf("Register values are: ");
for (int i=0; i<4; i++ )
 {
   printf("%02X ",SPI_RCV[i]);
 }
printf("\n");
 return 0;
}
gcc -o spitest spitest.c

RPI_333333
Posts: 13
Joined: Wed Nov 14, 2018 8:53 am

Re: Using SPI on python

Wed Dec 05, 2018 6:48 am

danjperron wrote:
Tue Dec 04, 2018 3:15 pm
the bcm2835 library uses direct access to the hardware.

Maybe you have something wrong with the device driver.


What is your /boot/config.txt ?
whats is the result of ls -l /dev/spi* ?
Which version of python are you using ? (python2 or python3) Did it fail on both python

Maybe try this version of C using IOCTL. If it works then it's not the device driver.

Code: Select all

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/spi/spidev.h>
#include <stdint.h>


int spi_handle=-1;
int spi_speed=1000000;


uint8_t spi_init(void) {
        int status_value = -1;
//        unsigned char spi_mode=SPI_MODE0|SPI_LSB_FIRST;
        unsigned char spi_mode=SPI_MODE_0;
        unsigned char spi_bitsPerWord=8;

        spi_handle = open("/dev/spidev0.0",O_RDWR);

       if(spi_handle < 0)
         {
           perror("Error - Could not open SPI device");
           exit(1);
         }


      status_value = ioctl(spi_handle, SPI_IOC_WR_MODE, &spi_mode);
      if(status_value < 0)
      {
        perror("Could not set SPIMode (WR)...ioctl fail");
        exit(1);
      }

      status_value = ioctl(spi_handle, SPI_IOC_RD_MODE, &spi_mode);
      if(status_value < 0)
      {
       perror("Could not set SPIMode (RD)...ioctl fail");
       exit(1);
      }

      status_value = ioctl(spi_handle, SPI_IOC_WR_BITS_PER_WORD, &spi_bitsPerWord);
      if(status_value < 0)
      {
      perror("Could not set SPI bitsPerWord (WR)...ioctl fail");
      exit(1);
      }

      status_value = ioctl(spi_handle, SPI_IOC_RD_BITS_PER_WORD, &spi_bitsPerWord);
      if(status_value < 0)
    {
      perror("Could not set SPI bitsPerWord(RD)...ioctl fail");
      exit(1);
    }

    status_value = ioctl(spi_handle, SPI_IOC_WR_MAX_SPEED_HZ, &spi_speed);
    if(status_value < 0)
    {
      perror("Could not set SPI speed (WR)...ioctl fail");
      exit(1);
    }

    status_value = ioctl(spi_handle, SPI_IOC_RD_MAX_SPEED_HZ, &spi_speed);
    if(status_value < 0)
    {
      perror("Could not set SPI speed (RD)...ioctl fail");
      exit(1);
    }
    return(1);
}




void spi_transfer(unsigned char *txbuff, unsigned char *rxbuff, int len)
{
  int ret;
  struct spi_ioc_transfer spi_tr = {
                .tx_buf = (unsigned long)  txbuff,
                .rx_buf = (unsigned long)  rxbuff,
                .len = len,
                .delay_usecs = 0,
                .speed_hz = spi_speed,  // speed in KHz to Hz
                .bits_per_word = 8,
              };
        ret = ioctl(spi_handle,SPI_IOC_MESSAGE(1), &spi_tr);
        if(ret < 1)
         {
          perror("Can't send spi message\n");
          close(spi_handle);
          exit(2);
        }
}




int main(void)
{
unsigned char SPI_TXM[]={0x40,0x00,0x00,0x00};
unsigned char SPI_RCV[4];


//Init SPI
if (!spi_init())
  {
    printf("IOCTL SPI failed \n");
    return 1;
  }
  printf("Init complete\n");


spi_transfer(SPI_TXM,SPI_RCV, 4);

printf("Register values are: ");
for (int i=0; i<4; i++ )
 {
   printf("%02X ",SPI_RCV[i]);
 }
printf("\n");
 return 0;
}
gcc -o spitest spitest.c

Hi, Thanks for the answers.
I tried with python 3 and 2.7- same result (Nothing on the piscope).

I tried the code you posted.
I get:
Init complete
Register values are: 00 00 00 00

At the Piscope there is still nothing (No clock , no nothing)

My boot/config.txt is:

Code: Select all

# For more options and information see
# http://rpf.io/configtxt
# Some settings may impact device functionality. See link above for details

# uncomment if you get no picture on HDMI for a default "safe" mode
#hdmi_safe=1

# uncomment this if your display has a black border of unused pixels visible
# and your display can output without overscan
#disable_overscan=1

# uncomment the following to adjust overscan. Use positive numbers if console
# goes off screen, and negative if there is too much border
#overscan_left=16
#overscan_right=16
#overscan_top=16
#overscan_bottom=16

# uncomment to force a console size. By default it will be display's size minus
# overscan.
#framebuffer_width=1280
#framebuffer_height=720

# uncomment if hdmi display is not detected and composite is being output
hdmi_force_hotplug=1

# uncomment to force a specific HDMI mode (this will force VGA)
hdmi_group=2
hdmi_mode=82

# uncomment to force a HDMI mode rather than DVI. This can make audio work in
# DMT (computer monitor) modes
#hdmi_drive=2

# uncomment to increase signal to HDMI, if you have interference, blanking, or
# no display
#config_hdmi_boost=4

# uncomment for composite PAL
#sdtv_mode=2

#uncomment to overclock the arm. 700 MHz is the default.
#arm_freq=800

# Uncomment some or all of these to enable the optional hardware interfaces
#dtparam=i2c_arm=on
#dtparam=i2s=on
dtparam=spi=on

# Uncomment this to enable the lirc-rpi module
#dtoverlay=lirc-rpi

# Additional overlays and parameters are documented /boot/overlays/README

# Enable audio (loads snd_bcm2835)
dtparam=audio=on
start_x=1
gpu_mem=128


When i try ls -l /dev/spi* i get:

Code: Select all

crw-rw---- 1 root spi 153, 0 Nov 30 16:55 /dev/spidev0.0
crw-rw---- 1 root spi 153, 1 Nov 30 16:55 /dev/spidev0.1


What could be the problem, why the BCM2835 activate the SPI connection but other libaries doesn't ?
Maybe i should re-install something ?
Is there any other check i can do?

Thanks for all the answers!

User avatar
joan
Posts: 13655
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Using SPI on python

Wed Dec 05, 2018 8:53 am

Are you a member of group spi?

groups

will list your groups.

If you do not see spi enter the command

sudo adduser pi spi

You will need to logout and log back in for a group change to take effect.

RPI_333333
Posts: 13
Joined: Wed Nov 14, 2018 8:53 am

Re: Using SPI on python

Wed Dec 05, 2018 9:06 am

joan wrote:
Wed Dec 05, 2018 8:53 am
Are you a member of group spi?

groups

will list your groups.

If you do not see spi enter the command

sudo adduser pi spi

You will need to logout and log back in for a group change to take effect.
I checked- i am a member in spi group

Any other ideas ?
please help guys...

User avatar
joan
Posts: 13655
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Using SPI on python

Wed Dec 05, 2018 12:12 pm

Let's just confirm the wiring is correct.

Start the pigpio daemon if it isn't running.

sudo pigpiod

Get a handle to SPI 0.0

pigs spio 0 50000 0

That should return handle 0.

Transfer 4 bytes to handle 0.

pigs spix 0 0x40 0 0 0

That should return 4 (the number of bytes transferred) followed by the returned data bytes.

RPI_333333
Posts: 13
Joined: Wed Nov 14, 2018 8:53 am

Re: Using SPI on python

Wed Dec 05, 2018 12:34 pm

joan wrote:
Wed Dec 05, 2018 12:12 pm
Let's just confirm the wiring is correct.

Start the pigpio daemon if it isn't running.

sudo pigpiod

Get a handle to SPI 0.0

pigs spio 0 50000 0

That should return handle 0.

Transfer 4 bytes to handle 0.

pigs spix 0 0x40 0 0 0

That should return 4 (the number of bytes transferred) followed by the returned data bytes.

I get:

Code: Select all

pigs spio 0 50000 0
result : 0

pigs spix 0 0x40 0 0 0
result : 4 0 0 0 


User avatar
joan
Posts: 13655
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Using SPI on python

Wed Dec 05, 2018 1:45 pm

That's unfortunate. I would have expected the same return values as you got from your first C program (255 255 48 17).

RPI_333333
Posts: 13
Joined: Wed Nov 14, 2018 8:53 am

Re: Using SPI on python

Wed Dec 05, 2018 2:02 pm

joan wrote:
Wed Dec 05, 2018 1:45 pm
That's unfortunate. I would have expected the same return values as you got from your first C program (255 255 48 17).
Oh !
sorry, i mistyped...

The result is indeed what you expected !

Code: Select all

pigs spix 0 0x40 0 0 0
Result: 4 255 255 48 17


So what can we learn from that ?

danjperron
Posts: 3141
Joined: Thu Dec 27, 2012 4:05 am
Location: Québec, Canada

Re: Using SPI on python

Wed Dec 05, 2018 2:15 pm

Ok from the C code I posted.


Could you remove everything from the SPI GPIO, run my spitest and report the values.
Then short together MISO and MOSI, at the rasberry Pi of course with nothing else, run spitest and report the values.

The first report should all 00 or 0Xff
the second test should be an echo of 0x40 x00 x00 0x00.

At least this is what I got and should have.

This is to verify if the spi works. You should try it using python also.

If it doesn't work, try with a fresh SD card with the latest raspbian just in case.

User avatar
joan
Posts: 13655
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Using SPI on python

Wed Dec 05, 2018 4:09 pm

The pigs version (like the working C program) bypasses the Linux SPI driver. So the SPI hardware is okay and the wiring is correct.

This suggest the Linux SPI driver is corrupted or misconfigured.

I'd be tempted to write a new image to the SD card.

RPI_333333
Posts: 13
Joined: Wed Nov 14, 2018 8:53 am

Re: Using SPI on python

Sun Dec 09, 2018 5:38 am

joan wrote:
Wed Dec 05, 2018 4:09 pm
The pigs version (like the working C program) bypasses the Linux SPI driver. So the SPI hardware is okay and the wiring is correct.

This suggest the Linux SPI driver is corrupted or misconfigured.

I'd be tempted to write a new image to the SD card.
I re-installed the RPI software and now it works!
Thanks for all the answers!

I love this forum :)

Return to “Python”