pnaven03
Posts: 130
Joined: Thu Feb 16, 2017 5:21 pm

Unable to read adc data from SPI0 bus in raspberry pi 3

Wed Sep 26, 2018 4:28 am

Hi Team,

I am connected two mcp3008 ADC chips to SPI0 bus, I am trying to read two adc chips data continuously but first adc channels data adding in seconds adc channels,i connected pot for testing. Please provide any solution for this issues.

My requirement is to read three adc modules data continuously It is possible to connect three adc chips to SPI0 bus, As my understand SPI1 bus supporting to three adc chips, enabled SPI1 bus in /boot/config.txt file.below same code support in SPI1 bus ?

My code :

bcm2835_spi_begin();
bcm2835_spi_setBitOrder(BCM2835_SPI_BIT_ORDER_MSBFIRST);
bcm2835_spi_setDataMode(BCM2835_SPI_MODE0);
bcm2835_spi_setClockDivider(BCM2835_SPI_CLOCK_DIVIDER_65536);

bcm2835_spi_chipSelect(BCM2835_SPI_CS0);
bcm2835_spi_setChipSelectPolarity(BCM2835_SPI_CS0, LOW); // the default
for(i=0;i<8;i++)
{
adc_data=0;
adc_voltage=0;
adc_data = readADC(i);
adc_voltage = volts_adc(adc_data);
printf("adc voltage = %f\n",adc_voltage);
}
bcm2835_spi_setChipSelectPolarity(BCM2835_SPI_CS0, HIGH);

bcm2835_spi_chipSelect(BCM2835_SPI_CS1);
bcm2835_spi_setChipSelectPolarity(BCM2835_SPI_CS1, LOW);
for(i=0;i<8;i++)
{
adc_data=0;
adc_voltage=0;
adc_data = readADC1(i);
adc_voltage = volts_adc1(adc_data);
printf("adc voltage = %f\n",adc_voltage);
}
bcm2835_spi_setChipSelectPolarity(BCM2835_SPI_CS1, HIGH);


Logs :

ADC1 Data :

adc voltage = 3.235484
adc voltage = 3.177419
adc voltage = 3.196774
adc voltage = 3.212903
adc voltage = 3.245161
adc voltage = 3.245161
adc voltage = 3.296774
adc voltage = 3.293548

ADC2 Data:

adc voltage = 2.577419
adc voltage = 1.748387
adc voltage = 1.748387
adc voltage = 1.748387
adc voltage = 1.748387
adc voltage = 1.748387
adc voltage = 1.748387
adc voltage = 1.748387

ADC voltage 2.57 updating in ADC2 data but this data is ADC1 data, Some times data is not coming properly.

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

Re: Unable to read adc data from SPI0 bus in raspberry pi 3

Wed Sep 26, 2018 1:33 pm

We need more of your code. Could you post the full code into gist.github.com.

Any reason why you are using the bcm2835 library ?

You know that just a simple file open with ioctl call works fine. Everything in Linux is a file.

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

Re: Unable to read adc data from SPI0 bus in raspberry pi 3

Wed Sep 26, 2018 1:54 pm

The other method is to enable the driver for mcp3008 .

https://github.com/scottellis/mcp3008-poll

sudo nano /boot/config.txt

Code: Select all

dtparam=spi=on
dtoverlay=mcp3008,spi0-0-present=true,spi0-0-speed=1000000
dtoverlay=mcp3008,spi0-1-present=true,spi0-1-speed=1000000
This way you will have 2 devices

Code: Select all

[email protected]:/sys/bus/iio/devices $ ls
iio:device0  iio:device1

pnaven03
Posts: 130
Joined: Thu Feb 16, 2017 5:21 pm

Re: Unable to read adc data from SPI0 bus in raspberry pi 3

Wed Sep 26, 2018 2:17 pm

Thank you so much for reply,

We are able to read two adc chips data (mcp3008) using SPI0, My requirement is to read three adc chips data(mcp3008), by using spi0 not possible as my understand, am trying to read three adc chips data from SPI1 but unable to read data.

My configuration in config file :

dtoverlay=spi1-3cs
dtoverlay=pi3-disable-bt


Source code attached.

int main(int argc, char **argv)
{
int adc_data=0,i=0;
float adc_voltage=0;

if (!bcm2835_init())
{
printf("bcm2835_init failed. Are you running as root??\n");
return 1;
}
bcm2835_spi_begin();
bcm2835_spi_setBitOrder(BCM2835_SPI_BIT_ORDER_MSBFIRST); // The default
bcm2835_spi_setDataMode(BCM2835_SPI_MODE0); // The default
bcm2835_spi_setClockDivider(BCM2835_SPI_CLOCK_DIVIDER_256); //256 512 65536 // The default

while(1)
{
///////////////////////////// Chip Select 0 //////////////////////////////////////////////
bcm2835_spi_chipSelect(BCM2835_SPI_CS0);
bcm2835_spi_setChipSelectPolarity(BCM2835_SPI_CS0, LOW); // the default
for(i=0;i<8;i++)
{
adc_data = readADC(i);
adc_voltage = volts_adc(adc_data);
printf("adc_1 voltage = %f\n",adc_voltage);
}

///////////////////////////// Chip select 1 /////////////////////////////////////////////////
bcm2835_spi_chipSelect(BCM2835_SPI_CS1);
bcm2835_spi_setChipSelectPolarity(BCM2835_SPI_CS1, LOW); // the default
for(i=0;i<8;i++)
{
adc_data = readADC(i);
adc_voltage = volts_adc(adc_data);
printf("adc_2 voltage = %f\n",adc_voltage);
}

///////////////////////////// Chip select 2 /////////////////////////////////////////////////
bcm2835_spi_chipSelect(BCM2835_SPI_CS2);
bcm2835_spi_setChipSelectPolarity(BCM2835_SPI_CS2, LOW); // the defaul
for(i=0;i<8;i++)
{
adc_data = readADC(i);
adc_voltage = volts_adc(adc_data);
printf("adc_3 voltage = %f\n",adc_voltage);
}
}

bcm2835_spi_end();
bcm2835_close();

return 0;

}

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

Re: Unable to read adc data from SPI0 bus in raspberry pi 3

Wed Sep 26, 2018 2:22 pm

It may be a limitation of the bcm2835 library. When it was written only two SPI chip selects were official on SPI0.

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

Re: Unable to read adc data from SPI0 bus in raspberry pi 3

Wed Sep 26, 2018 2:42 pm

Thanks for your code but whereis the function readADC(i)?


There are other SPI devices available on the Raspberry Pi.

check /boot/overlays/README

You could enable SPI1 with 3 chip select

Code: Select all

dtoverlay=spi1-3cs,cs0_spidev=disabled
I disabled cs0 since you are using PWM0 for your led strip

Code: Select all

[email protected]:~ $ ls -l /dev/spidev1*
crw-rw---- 1 root spi 153, 1 sep 26 10:34 /dev/spidev1.1
crw-rw---- 1 root spi 153, 0 sep 26 10:34 /dev/spidev1.2
SPI1_CLK GPIO21
SPI1_MOSI GPIO20
SPI1_MISO GPIO19
SPI1_CS1 GPIO17
SPI1_CS2 GPIO16

You could simply open an handle

Code: Select all

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);
      }
      
      etc.....
      
      
      void my_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 * 1000,  // 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);
        }
}
      
      
     

pnaven03
Posts: 130
Joined: Thu Feb 16, 2017 5:21 pm

Re: Unable to read adc data from SPI0 bus in raspberry pi 3

Wed Sep 26, 2018 2:52 pm

Thanks for the reply,

My ADC read function :

int readADC(uint8_t chan)
{
char buf[] = {start, (0x08|chan)<<4,end};
char readBuf[3]={0};
bcm2835_spi_transfernb(buf,readBuf,3);
return ((int)readBuf[1] & 0x03) << 8 | (int) readBuf[2];
}

float volts_adc(int adc)
{
return (float)adc*3.3f/1023.0f;
}


I am enabled SPI1 with three chip select.

The above not support to SPI1 ?

Added sample code if any links working code please provide me.

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

Re: Unable to read adc data from SPI0 bus in raspberry pi 3

Wed Sep 26, 2018 3:40 pm

I won't be able to code today.

I do have some MCP3008. but I will be home very late tonight!


But for ioctl access with SPI check this webpage. http://www.hertaville.com/interfacing-a ... ing-c.html
It is written in c++

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

Re: Unable to read adc data from SPI0 bus in raspberry pi 3

Wed Sep 26, 2018 5:56 pm

Ok at lunch time I did this code.

I assume that spidev0.0 ,spidev0.1 and spidev1.1 are enabled and each one has a mcp3008 connected.

I didn't test the code , no mcp3008 with me, then it is possible that it needs some modification

Code: Select all

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

#define NB_MCP3008 3
#define SPI_SPEED 1000000

// MCP3008 handles
   int mcp3008Handle[NB_MCP3008]={-1,-1,-1};
   char * mcp3008DeviceName[NB_MCP3008]={"/dev/spidev0.0",\
                                     "/dev/spidev0.1",\
                                     "/dev/spidev1.1"};


///  SPI STUFF

int openSPI(char *spidev)
{
    int spi_handle;
    unsigned char spi_mode=0;
    unsigned char spi_bitsPerWord=8;
    unsigned long  _spi_speed =SPI_SPEED;

    spi_handle = open(spidev,O_RDWR);

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

     ioctl(spi_handle, SPI_IOC_WR_MODE, &spi_mode);
     ioctl(spi_handle, SPI_IOC_WR_BITS_PER_WORD, &spi_bitsPerWord);
     ioctl(spi_handle, SPI_IOC_WR_MAX_SPEED_HZ, &_spi_speed);

    return(spi_handle);
}

int my_spi_transfer(int spi_handle,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,
                .bits_per_word = 8,
              };
        ret = ioctl(spi_handle,SPI_IOC_MESSAGE(1), &spi_tr);
        if(ret < 1)
         {
          perror("Can't send spi message\n");
          return 0;
        }
 return 1;
}



// MCP3008 FUNCTION
// read_adc(spi_handle,singleDiff,channel)
// spi_handle  handle of the SPI
// singleDIFF  !0= single  0=Differential
// channel     channel 0 to 7 to read
//
// return  -1 if error otherwise the A2D value between 0 and 1023

int read_adc(int spi_handle,int singleDiff,int channel)
{
   unsigned char data[3];
    short value;
   if(spi_handle <0) return -1; // is spi handle valid
   if((channel <0) || (channel > 7)) return -1; // if channel number valid

   data[0]=1;  // start bit
   data[1]=  (singleDiff ? 0x80 : 0) | ( channel <<4);
   data[2]=0;
   if(my_spi_transfer(spi_handle,data,data,3))
     {
       value = (((unsigned short) data[1] )<<8) & 0x300;
       value |= data[2];
       return value;
     }
return -1;
}


void myExit(void)
{
  int loop;

   for(loop=0;loop<NB_MCP3008;loop++)
      if(mcp3008Handle[loop]>=0)
        {
          close(mcp3008Handle[loop]);
          mcp3008Handle[loop]=-1;
        }
}



int main(void)
{
  int loop;
  int channel;
  atexit(myExit);

  for(loop=0;loop<NB_MCP3008;loop++)
   {
     mcp3008Handle[loop]= openSPI(mcp3008DeviceName[loop]);
     if(mcp3008Handle[loop]<0)
          return 1;
   }

// read the A/D

  for(loop=0;loop<NB_MCP3008;loop++)
   {
      printf("\nMCP3008 #%d %s\n==========\n",loop+1,mcp3008DeviceName[loop]);
      for(channel=0;channel<8;channel++)
        printf("Channel %d: %d\n",channel,read_adc(mcp3008Handle[loop],1,channel));
   }

  return 0;
}

Last edited by danjperron on Thu Sep 27, 2018 4:54 pm, edited 1 time in total.

User avatar
mikronauts
Posts: 2643
Joined: Sat Jan 05, 2013 7:28 pm
Contact: Website

Re: Unable to read adc data from SPI0 bus in raspberry pi 3

Wed Sep 26, 2018 10:36 pm

Take a peek at my article at

http://www.mikronauts.com/raspberry-pi/ ... and-howto/

It does need an external 3:8 demux, but it allows you to use just one of the SPI /CS signals and decode to eight SPI peripherals by using three GPIO's to decide which of eight SPI devices you want to address.

You could do something similar with the overlay that lets you re-purpose other GPIO and skip the chip, but I am not sure that would work with the BCM library you are using.
pnaven03 wrote:
Wed Sep 26, 2018 4:28 am
Hi Team,

I am connected two mcp3008 ADC chips to SPI0 bus, I am trying to read two adc chips data continuously but first adc channels data adding in seconds adc channels,i connected pot for testing. Please provide any solution for this issues.

My requirement is to read three adc modules data continuously It is possible to connect three adc chips to SPI0 bus, As my understand SPI1 bus supporting to three adc chips, enabled SPI1 bus in /boot/config.txt file.below same code support in SPI1 bus ?

My code :

bcm2835_spi_begin();
bcm2835_spi_setBitOrder(BCM2835_SPI_BIT_ORDER_MSBFIRST);
bcm2835_spi_setDataMode(BCM2835_SPI_MODE0);
bcm2835_spi_setClockDivider(BCM2835_SPI_CLOCK_DIVIDER_65536);

bcm2835_spi_chipSelect(BCM2835_SPI_CS0);
bcm2835_spi_setChipSelectPolarity(BCM2835_SPI_CS0, LOW); // the default
for(i=0;i<8;i++)
{
adc_data=0;
adc_voltage=0;
adc_data = readADC(i);
adc_voltage = volts_adc(adc_data);
printf("adc voltage = %f\n",adc_voltage);
}
bcm2835_spi_setChipSelectPolarity(BCM2835_SPI_CS0, HIGH);

bcm2835_spi_chipSelect(BCM2835_SPI_CS1);
bcm2835_spi_setChipSelectPolarity(BCM2835_SPI_CS1, LOW);
for(i=0;i<8;i++)
{
adc_data=0;
adc_voltage=0;
adc_data = readADC1(i);
adc_voltage = volts_adc1(adc_data);
printf("adc voltage = %f\n",adc_voltage);
}
bcm2835_spi_setChipSelectPolarity(BCM2835_SPI_CS1, HIGH);


Logs :

ADC1 Data :

adc voltage = 3.235484
adc voltage = 3.177419
adc voltage = 3.196774
adc voltage = 3.212903
adc voltage = 3.245161
adc voltage = 3.245161
adc voltage = 3.296774
adc voltage = 3.293548

ADC2 Data:

adc voltage = 2.577419
adc voltage = 1.748387
adc voltage = 1.748387
adc voltage = 1.748387
adc voltage = 1.748387
adc voltage = 1.748387
adc voltage = 1.748387
adc voltage = 1.748387

ADC voltage 2.57 updating in ADC2 data but this data is ADC1 data, Some times data is not coming properly.
http://Mikronauts.com - home of EZasPi, RoboPi, Pi Rtc Dio and Pi Jumper @Mikronauts on Twitter
Advanced Robotics, I/O expansion and prototyping boards for the Raspberry Pi

pnaven03
Posts: 130
Joined: Thu Feb 16, 2017 5:21 pm

Re: Unable to read adc data from SPI0 bus in raspberry pi 3

Thu Sep 27, 2018 5:16 am

Dear danjperron,

Appreciate for your technical support and Thank you so much.

Now am able to read three mcp3008 chips data from SPI1.

1. Enable in SPI1 in config file

dtoverlay=spi1-3cs

2. Modified source code

char * mcp3008DeviceName[NB_MCP3008]={"/dev/spidev1.0",\
"/dev/spidev1.1",\
"/dev/spidev1.2"};

* Added voltage calculation

return (float)value*3.3f/1023.0f;

3. Compiled and tested.

4. Added pot each mcp3008 chip and console voltage values conformed with pot using multimeter.

Return to “General discussion”