msmithy12
Posts: 94
Joined: Fri Aug 10, 2012 8:57 am

SPI wiringPi issue

Fri Apr 04, 2014 10:35 am

Hello (Im guessing Gordon will be straight on this but any one with info is welcome to comment)

So I had a Pi connected via UART to a PIC the PIC was then connected via SPI to an ADC (MCP3301) and the ADC was connected to a variable resistance. And everything worked fine. Measure resistance and feed it to Pi.

Anyway I though that the PIC was a bit redundant. So decided that the Pi via SPI would get the ADC read directly.

So I removed the PIC and made the nessesary Pi connections to the ADC.

I also have a nice little MCP23017 doing some I2C address control. But I think that is kinda irrelevant.

So using the wiringPiSPI.h I have been trying and failing to read the ADC. I get the errno No such file or directory.

I am sure this is a simple fix but I have been struggling a few days so thought I would open it to the forum

Code: Select all

#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/i2c-dev.h>
#include <linux/spi/spidev.h>
#include <stdlib.h>
#include <errno.h>
#include <wiringPiSPI.h>

#define I2C_ADDR 0x20            // Device adress
#define SPI_CH 0
#define SPI_SPD 8000000
#define SPI_SZ 16

//static const char *SPI_CH = "/dev/spidev0.0";
static const char *device = "/dev/i2c-1";   // I2C bus


void main()
{
   char cont;
   float ohms;
      int i;
   int fd;
      uint8_t buffer[2];
      set_i2c();
      wiringPiSetupSys();
   for(i = 0 ; i < 16; i++)
   {
      buffer[0] = 0x15;
      buffer[1] = i;
      int z = write(fd,buffer,2);      //Put i to port b (0x15)
      adc_read();
      printf("contact %u reading %f\n\r",i+1,ohms);
      delay(1000);
   }
   buffer[0] = 0x15;
   buffer[1] = 0x00;
   int z = write(fd,buffer,2);
   buffer[0] = 0x14;
   buffer[1] = 0b11000000;
   z = write(fd,buffer,2);
   for(i = 0 ; i < 16; i++)
   {
      buffer[0] = 0x15;
      buffer[1] = i;
      z = write(fd,buffer,2);      //Put i to port b (0x15)
      adc_read();
      printf("contact %u reading %f\n\r",i+1,ohms);
      delay(1000);
   }
   return;
}

adc_read()
{
int adc;
uint8_t buff[SPI_SZ];
float ohms = 3;


   delay(100);
   sel_chip();
   if(wiringPiSPISetup(SPI_CH,SPI_SPD) < 0);
   {
      fprintf(stderr,"Epic Fail: %s\n",strerror(errno));
      exit(1);
   }
   wiringPiSPIDataRW (SPI_CH,buff,SPI_SZ);

   desel_chip();
   adc = *buff;
   adc = ohms;
   return ohms;
}

desel_chip()
{
   int fd;
      uint8_t buffer[2];
   if ((fd = open(device, O_RDWR)) < 0 );
      if (ioctl(fd,I2C_SLAVE,I2C_ADDR) < 0);
      buffer[0] = 0x14;
      buffer[1] = 0b01000000;
      int z = write(fd,buffer,2);
}

sel_chip()
{
   int fd;
      uint8_t buffer[2];
   if ((fd = open(device, O_RDWR)) < 0 );
      if (ioctl(fd,I2C_SLAVE,I2C_ADDR) < 0);
      buffer[0] = 0x14;
      buffer[1] = 0b00000000;
      int z = write(fd,buffer,2);
}

set_i2c()
{
   int fd;
      uint8_t buffer[2];

      //##Write to i2c##
      if ((fd = open(device, O_RDWR)) < 0 );
      if (ioctl(fd,I2C_SLAVE,I2C_ADDR) < 0);
      buffer[0] = 0x00;            //
      buffer[1] = 0x00;            //
      int z = write(fd,buffer,2);      //Set Port A (0x00) to Output (0x00)
      buffer[0] = 0x01;            //
      buffer[1] = 0x00;            //
      z = write(fd,buffer,2);         //Set Port B (0x01) to Output (0x00)
      if(z<0)
         fputs("setup fail\n\r", stderr);

   buffer[0] = 0x14;
   buffer[1] = 0b01000000;
   z = write(fd,buffer,2);         //deselect ADC chip
      delay(100);
}


I am using one of the MCP23017 pins as a /CS pin.

Please excuse my poor spelling/grammar I am an engineer :)
I assume I know what I`m talking about... I probably don`t

Home: 256mb Made in UK, Rasbmc, 40" Sony Bravia KDL-40v3000
Work: 2b+, Rasbian, 6" Lilliput touchscreen

techpaul
Posts: 1512
Joined: Sat Jul 14, 2012 6:40 pm
Location: Reading, UK
Contact: Website

Re: SPI wiringPi issue

Sat Apr 05, 2014 8:21 am

msmithy12 wrote:Hello (Im guessing Gordon will be straight on this but any one with info is welcome to comment)

So I had a Pi connected via UART to a PIC the PIC was then connected via SPI to an ADC (MCP3301) and the ADC was connected to a variable resistance. And everything worked fine. Measure resistance and feed it to Pi.

Anyway I though that the PIC was a bit redundant. So decided that the Pi via SPI would get the ADC read directly.

So I removed the PIC and made the nessesary Pi connections to the ADC.

I also have a nice little MCP23017 doing some I2C address control. But I think that is kinda irrelevant.

So using the wiringPiSPI.h I have been trying and failing to read the ADC. I get the errno No such file or directory.
Which sounds as like either you have not enabled SPI on the Pi of if compilation error not installed all relevant parts.
I am using one of the MCP23017 pins as a /CS pin.
Which most likely will NOT work as expected as you need to gate the relevant ADC selection with the CS signal from the Pi as this needs to be synchronised as part of the SPI transaction as CS going low will start device doing what it is supposed to do and going high will end the action. This could cause problems if multiple devices on same MISO lines as the CS determines which one comes out of tri-state mode to drive the line and you could end up with multiple devices driving the one line.

How many ADCs are you using?

Easier solution for CS select is something like 74xx138 to gate the CS line to 8 devices and 3 GPIO lines for which one to select. Also allows an extra GPIO to use as selector enable to avoid startup issues of unknown GPIO states at power up causing any CS induced lockups.
Just another techie on the net - For GPIO boards see http:///www.facebook.com/pcservicesreading
or http://www.pcserviceselectronics.co.uk/pi/

msmithy12
Posts: 94
Joined: Fri Aug 10, 2012 8:57 am

Re: SPI wiringPi issue

Mon Apr 07, 2014 11:06 am

Hi, Thanks for the speedy reply. I went back to basics this morning before I saw the reply.

I stared by checking the spi module with

Code: Select all

lsmod
and that shows spi_bcm2708 listed so I copied the spidev_test.c file on the website and compiled it. But when it ran I still got an error. Which makes me think I have the module loaded wrong.

I will do some more digging and post back later
I assume I know what I`m talking about... I probably don`t

Home: 256mb Made in UK, Rasbmc, 40" Sony Bravia KDL-40v3000
Work: 2b+, Rasbian, 6" Lilliput touchscreen

User avatar
gordon@drogon.net
Posts: 2022
Joined: Tue Feb 07, 2012 2:14 pm
Location: Devon, UK
Contact: Website Twitter

Re: SPI wiringPi issue

Mon Apr 07, 2014 11:56 am

msmithy12 wrote:Hello (Im guessing Gordon will be straight on this but any one with info is welcome to comment)
Not always - best to email if you really want to get in-touch...

So I had a Pi connected via UART to a PIC the PIC was then connected via SPI to an ADC (MCP3301) and the ADC was connected to a variable resistance. And everything worked fine. Measure resistance and feed it to Pi.

Anyway I though that the PIC was a bit redundant. So decided that the Pi via SPI would get the ADC read directly.

So I removed the PIC and made the nessesary Pi connections to the ADC.

I also have a nice little MCP23017 doing some I2C address control. But I think that is kinda irrelevant.

So using the wiringPiSPI.h I have been trying and failing to read the ADC. I get the errno No such file or directory.

I am sure this is a simple fix but I have been struggling a few days so thought I would open it to the forum

Code: Select all

#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/i2c-dev.h>
#include <linux/spi/spidev.h>
#include <stdlib.h>
#include <errno.h>
#include <wiringPiSPI.h>

#define I2C_ADDR 0x20            // Device adress
#define SPI_CH 0
#define SPI_SPD 8000000
#define SPI_SZ 16

//static const char *SPI_CH = "/dev/spidev0.0";
static const char *device = "/dev/i2c-1";   // I2C bus


void main()
{
   char cont;
   float ohms;
      int i;
   int fd;
      uint8_t buffer[2];
      set_i2c();
      wiringPiSetupSys();
   for(i = 0 ; i < 16; i++)
   {
      buffer[0] = 0x15;
      buffer[1] = i;
      int z = write(fd,buffer,2);      //Put i to port b (0x15)
      adc_read();
      printf("contact %u reading %f\n\r",i+1,ohms);
      delay(1000);
   }
   buffer[0] = 0x15;
   buffer[1] = 0x00;
   int z = write(fd,buffer,2);
   buffer[0] = 0x14;
   buffer[1] = 0b11000000;
   z = write(fd,buffer,2);
   for(i = 0 ; i < 16; i++)
   {
      buffer[0] = 0x15;
      buffer[1] = i;
      z = write(fd,buffer,2);      //Put i to port b (0x15)
      adc_read();
      printf("contact %u reading %f\n\r",i+1,ohms);
      delay(1000);
   }
   return;
}

adc_read()
{
int adc;
uint8_t buff[SPI_SZ];
float ohms = 3;


   delay(100);
   sel_chip();
   if(wiringPiSPISetup(SPI_CH,SPI_SPD) < 0);
   {
      fprintf(stderr,"Epic Fail: %s\n",strerror(errno));
      exit(1);
   }
   wiringPiSPIDataRW (SPI_CH,buff,SPI_SZ);

   desel_chip();
   adc = *buff;
   adc = ohms;
   return ohms;
}

desel_chip()
{
   int fd;
      uint8_t buffer[2];
   if ((fd = open(device, O_RDWR)) < 0 );
      if (ioctl(fd,I2C_SLAVE,I2C_ADDR) < 0);
      buffer[0] = 0x14;
      buffer[1] = 0b01000000;
      int z = write(fd,buffer,2);
}

sel_chip()
{
   int fd;
      uint8_t buffer[2];
   if ((fd = open(device, O_RDWR)) < 0 );
      if (ioctl(fd,I2C_SLAVE,I2C_ADDR) < 0);
      buffer[0] = 0x14;
      buffer[1] = 0b00000000;
      int z = write(fd,buffer,2);
}

set_i2c()
{
   int fd;
      uint8_t buffer[2];

      //##Write to i2c##
      if ((fd = open(device, O_RDWR)) < 0 );
      if (ioctl(fd,I2C_SLAVE,I2C_ADDR) < 0);
      buffer[0] = 0x00;            //
      buffer[1] = 0x00;            //
      int z = write(fd,buffer,2);      //Set Port A (0x00) to Output (0x00)
      buffer[0] = 0x01;            //
      buffer[1] = 0x00;            //
      z = write(fd,buffer,2);         //Set Port B (0x01) to Output (0x00)
      if(z<0)
         fputs("setup fail\n\r", stderr);

   buffer[0] = 0x14;
   buffer[1] = 0b01000000;
   z = write(fd,buffer,2);         //deselect ADC chip
      delay(100);
}


I am using one of the MCP23017 pins as a /CS pin.

Please excuse my poor spelling/grammar I am an engineer :)
Where to start...

wiringPi directly supports the mcp23017 I2C GPIO expander chips. See examples here:

http://wiringpi.com/extensions/i2c-mcp23008-mcp23017/

However you should be able to run your ADC chip without that - the Pi's SPI bus has a /CS line - actually it has 2.

Calling wiringPiSPISetup() more than once per channel per program run is a bad thing. You'll eventually run out of file-descriptors. Just call it once, after wiringPiSetup()

Make sure the drivers are loaded:

Code: Select all

gpio load spi
gpio load i2c
Then give it a go. you'll need to run your program with sudo unless you use the gpio command to load the modules.

However I'm not sure what your code is doing with:

Code: Select all

   adc = *buff;
   adc = ohms;
That's going to return 3 (what you set ohms to) regardless. (and adc = *buff; will only work if it's an 8-bit ADC and the return value is in the first byte - I've not checked the data sheet yet)

there's lots more somewhat sub-optimal coding there too, but I'm guessing you're a fairly new C programmer - ohms is a float, and the function returns an integer. Try compiling it with -Wall and fix the warnings it gives.

Ultimately it might be easy to write a wiringPi driver for the device, then it's just a matter of calling its setup code and then using x = analogRead (0), etc.


-Gordon
--
Gordons projects: https://projects.drogon.net/

msmithy12
Posts: 94
Joined: Fri Aug 10, 2012 8:57 am

Re: SPI wiringPi issue

Mon Apr 07, 2014 12:52 pm

I don't like to email people directly, Especially on opensource topics like wiringPI.

Today I have learnt that CE0 and CE1 stand for Chip Enable, which is similar to (exactly the same as) CS, chip select. Which makes life easier.

As for the ohms = 3 that was just to get an output other than 0 for debugging (that i should have removed prior to uploading).

I am fairly new to C and have been scouring google for sample code and then modifying it to my own needs, which I imagine is frowned upon but if I learn how/why the code is working (or not working) then it cant be all that bad.

I have been compiling with a make file. (The same style makefile I have been using for some gtk-wiringpi led flashing stuff) With each program having a folder to keep stuff separate.

Code: Select all

CC = gcc
CFLAGS = `pkg-config --cflags gtk+-3.0`
LIBS = `pkg-config --libs gtk+-3.0`

test: test.o
$(CC) $(LIBS) -Wall -g -o test test.o -std=c99 -Wl --export-dynamic -lWiringPi

test.o: test.c
$(CC) $(LIBS) -c test.c
Although now I look at it I cant remember why I have used C99

Once I have the code working I will try some optimising.
I assume I know what I`m talking about... I probably don`t

Home: 256mb Made in UK, Rasbmc, 40" Sony Bravia KDL-40v3000
Work: 2b+, Rasbian, 6" Lilliput touchscreen

msmithy12
Posts: 94
Joined: Fri Aug 10, 2012 8:57 am

Re: SPI wiringPi issue

Wed Apr 09, 2014 2:31 pm

I have ditched (well more like shelved until further notice) that code after realising I was trying to fly when I couldn't really walk.

What I have now is just the MCP3301 on the SPI and I am trying to read the ADC value. I know gordon suggested writing a wiringpi driver for the MCP3301, But I didn`t know where to start. So I have started to write some SPI code just to read the ADC as shown below.

Code: Select all

#include <stdio.h>
#include <linux/types.h>
#include <linux/i2c-dev.h>
#include <linux/spi/spidev.h>
#include <stdlib.h>
#include <errno.h>
#include <wiringPiSPI.h>

#define SPI_CH 0 //spi channel
#define SPI_SPD 1000000 //spi speed
#define SPI_SZ 8  //spi size

void main()
{
   set_spi();
for(;;){
   delay(1000);
   adc_read();
}
}

adc_read()
{
   int z;
   unsigned char buff[SPI_SZ];
   wiringPiSPIDataRW(SPI_CH,buff,SPI_SPD);
   for(z=0;z<SPI_SZ;++z){
   printf("%d,",buff[z]);
   }
   printf("\n\r");
}

set_spi()
{
      wiringPiSetupSys();
   if (wiringPiSPISetup(SPI_CH,SPI_SPD) <0)
      fprintf(stderr,"EPIC FAIL:%s\n\r",strerror(errno));
I believe that I have to send a control bit somewhere in

Code: Select all

buff[]
but I am not sure how/where. When I used this chip with a PIC i just used

Code: Select all

x1 =spi_read()
x2=spi_read()
and moved the values.

I have looked at the data sheet http://ww1.microchip.com/downloads/en/D ... 21700D.pdf but I am struggling to find a place to start.

Eventually this will all become part of a environment monitoring system.

Also I cant see the CE0 clocking low (using my scope) is that an issue?
I assume I know what I`m talking about... I probably don`t

Home: 256mb Made in UK, Rasbmc, 40" Sony Bravia KDL-40v3000
Work: 2b+, Rasbian, 6" Lilliput touchscreen

Return to “C/C++”