Marlboro A$CE
Posts: 3
Joined: Mon Jun 29, 2015 3:27 pm

Sample speed of MCP3008

Mon Jun 29, 2015 3:42 pm

Hi,
I want to use a MCP3008 to read the voltage of a microphone, I have a Raspberry PI 2.
I use WiringPI library to communicate with the ADC in SPI and it works but not at the expected speed.

I need minimum 190KHz but I barely cross the 14 KHz.
The MCP3008 datasheet from talking about maximum 200KHz. So it should work.
I think the problem comes from the communication speed SPI, I try to change it but without much effect. At best I capped at 14kHz.

here is my code :

Code: Select all

#include <wiringPi.h>
#include <mcp3004.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <time.h>

#define BASE 100
#define SPI_CHAN 0
#define AN_CHAN_DAC 0
#define FREQUENCE 150000

struct wiringPiNodeStruct *node ;

static int myAnalogRead (int pin)
{
  unsigned char spiData [3] ;
  unsigned char chanBits ;
  int chan = pin - node->pinBase ;

  chanBits = 0b10000000 | (chan << 4) ;

  spiData [0] = 1 ;		// Start bit
  spiData [1] = chanBits ;
  spiData [2] = 0 ;

  wiringPiSPIDataRW (node->fd, spiData, 3) ;

  return ((spiData [1] << 8) | spiData [2]) & 0x3FF ;
	}


/*
 * mcp3004Setup:
 *	Create a new wiringPi device node for an mcp3004 on the Pi's
 *	SPI interface.
 *********************************************************************************
 */

int mcp3004Setup (const int pinBase, int spiChannel)
{

  if (wiringPiSPISetup (spiChannel, 32000000) < 0)
    return -1 ;

  node = wiringPiNewNode (pinBase, 8) ;

  node->fd         = spiChannel ;

  return 0 ;
	}

int main(){
	int resultat[FREQUENCE];
	//int resultat;
	FILE * result;
	char arch[200];
	int j = 0;
	//double ts[FREQUENCE];
	double ts;
	struct timespec tm, deb, fin;
	
	
	printf("START Test SPI\n");
	wiringPiSetup();
	mcp3004Setup(BASE,SPI_CHAN);
	printf("Connection SPI OK\n");
	result = fopen("testSPI.txt","w+");

	int i;
	int n;
	printf("START\n");
	clock_gettime(CLOCK_REALTIME,&deb);
	
	for(i=0;i<FREQUENCE;i++){
			resultat[i] = myAnalogRead(BASE+AN_CHAN_DAC);
			}
	
	clock_gettime(CLOCK_REALTIME,&fin);
	printf("END\n");
	
	double t = (deb.tv_sec) + (deb.tv_nsec) * 0.000000001 ;
	fprintf(result,"%f\n", t);

	t = (fin.tv_sec) + (fin.tv_nsec) * 0.000000001 ;
	fprintf(result,"%f\n",t);

	t = t - (double)((deb.tv_sec) + (deb.tv_nsec) * 0.000000001);
	fprintf(result,"%f\n",t);
	
	printf("FILE : ");
	for(i=0;i<FREQUENCE;i++){
		fprintf(result,"%d\n",resultat[i]);
		}
		
	fclose(result);	
	printf("OK\n");
	return 0;
	}
	
Do you have an idea?
Thank you in advance.

User avatar
mikronauts
Posts: 2823
Joined: Sat Jan 05, 2013 7:28 pm

Re: Sample speed of MCP3008

Mon Jun 29, 2015 4:04 pm

Not a hope of sampling the MCP3008 at 190KHz

Get an I2S ADC, or a USB microphone.
Marlboro A$CE wrote:Hi,
I want to use a MCP3008 to read the voltage of a microphone, I have a Raspberry PI 2.
I use WiringPI library to communicate with the ADC in SPI and it works but not at the expected speed.

I need minimum 190KHz but I barely cross the 14 KHz.
The MCP3008 datasheet from talking about maximum 200KHz. So it should work.
I think the problem comes from the communication speed SPI, I try to change it but without much effect. At best I capped at 14kHz.

here is my code :

Code: Select all

#include <wiringPi.h>
#include <mcp3004.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <time.h>

#define BASE 100
#define SPI_CHAN 0
#define AN_CHAN_DAC 0
#define FREQUENCE 150000

struct wiringPiNodeStruct *node ;

static int myAnalogRead (int pin)
{
  unsigned char spiData [3] ;
  unsigned char chanBits ;
  int chan = pin - node->pinBase ;

  chanBits = 0b10000000 | (chan << 4) ;

  spiData [0] = 1 ;		// Start bit
  spiData [1] = chanBits ;
  spiData [2] = 0 ;

  wiringPiSPIDataRW (node->fd, spiData, 3) ;

  return ((spiData [1] << 8) | spiData [2]) & 0x3FF ;
	}


/*
 * mcp3004Setup:
 *	Create a new wiringPi device node for an mcp3004 on the Pi's
 *	SPI interface.
 *********************************************************************************
 */

int mcp3004Setup (const int pinBase, int spiChannel)
{

  if (wiringPiSPISetup (spiChannel, 32000000) < 0)
    return -1 ;

  node = wiringPiNewNode (pinBase, 8) ;

  node->fd         = spiChannel ;

  return 0 ;
	}

int main(){
	int resultat[FREQUENCE];
	//int resultat;
	FILE * result;
	char arch[200];
	int j = 0;
	//double ts[FREQUENCE];
	double ts;
	struct timespec tm, deb, fin;
	
	
	printf("START Test SPI\n");
	wiringPiSetup();
	mcp3004Setup(BASE,SPI_CHAN);
	printf("Connection SPI OK\n");
	result = fopen("testSPI.txt","w+");

	int i;
	int n;
	printf("START\n");
	clock_gettime(CLOCK_REALTIME,&deb);
	
	for(i=0;i<FREQUENCE;i++){
			resultat[i] = myAnalogRead(BASE+AN_CHAN_DAC);
			}
	
	clock_gettime(CLOCK_REALTIME,&fin);
	printf("END\n");
	
	double t = (deb.tv_sec) + (deb.tv_nsec) * 0.000000001 ;
	fprintf(result,"%f\n", t);

	t = (fin.tv_sec) + (fin.tv_nsec) * 0.000000001 ;
	fprintf(result,"%f\n",t);

	t = t - (double)((deb.tv_sec) + (deb.tv_nsec) * 0.000000001);
	fprintf(result,"%f\n",t);
	
	printf("FILE : ");
	for(i=0;i<FREQUENCE;i++){
		fprintf(result,"%d\n",resultat[i]);
		}
		
	fclose(result);	
	printf("OK\n");
	return 0;
	}
	
Do you have an idea?
Thank you in advance.
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

User avatar
DougieLawson
Posts: 42297
Joined: Sun Jun 16, 2013 11:19 pm
Location: A small cave in deepest darkest Basingstoke, UK

Re: Sample speed of MCP3008

Mon Jun 29, 2015 4:24 pm

What audio signal are you trying to detect? You'll probably do better with a dedicated USB audio card.
Languages using left-hand whitespace for syntax are ridiculous

DMs sent on https://twitter.com/DougieLawson or LinkedIn will be answered next month.
Fake doctors - are all on my foes list.

The use of crystal balls and mind reading is prohibited.

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

Re: Sample speed of MCP3008

Mon Jun 29, 2015 4:38 pm

You will do considerably better if you use my pigpio or the bcm2835 libraries for SPI. They both talk to the hardware directly and do not suffer from the 20k or so transactions per second limit of the Linux driver.

Marlboro A$CE
Posts: 3
Joined: Mon Jun 29, 2015 3:27 pm

Re: Sample speed of MCP3008

Tue Jun 30, 2015 7:39 am

Hi, and thanks for your answers.

I started my tests with a 1608G measurement of computing, it works but I'm unable to listen continuously. I am limited to 500 values per ​​acquisition phase.
When seeing in the datasheet of MCP3008 he could reach 200KHz at 5V I thought it was the right solution.
Not a hope of sampling the MCP3008 at 190KHz
Get an I2S ADC Gold USB microphone.
Why is it impossible? :cry: Can you be a little more precise, it is because of the PI or ADC?
What audio are you Trying to detect? You'll probably do better with a dedicated USB sound card.
I want to sample a signal from a hydrophone at a frequency of 180 ~ 200 kHz in order to detect a signal at 75 kHz (ultrasonic transmitter).
This is the basis of my project.
You will do considerably better if you use my pigpio or the bcm2835 libraries for SPI. They both talk to the hardware directly and do not suffer from the 20k or so transactions per second limit of the Linux driver.
Ok, WiringPI the library does not go through the hardware? Using GPIO and simulating an SPI communication, I reach 4KHz in python and if I use C I get to 180kHz, but the data fluctuate. Some are false. I thought solve my problem using the hardware module.

I'll look pigpio and bookstore bcm2835.

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

Re: Sample speed of MCP3008

Tue Jun 30, 2015 8:09 am

Marlboro A$CE wrote: ...
Ok, WiringPI the library does not go through the hardware? Using GPIO and simulating an SPI communication, I reach 4KHz in python and if I use C I get to 180kHz, but the data fluctuate. Some are false. I thought solve my problem using the hardware module.
wiringPi uses the Linux driver (or it did the last time I looked).

I guess by simulate you mean you have bit banged the lines.

The only problem I can see with bit banging is controlling the bit rate timing. The ADC needs time to do the sample and if you are bit banging it'll be hard to ensure the timing at the data rates you want. The fluctuations may well be down to fetching the sample before it is ready.

User avatar
mikronauts
Posts: 2823
Joined: Sat Jan 05, 2013 7:28 pm

Re: Sample speed of MCP3008

Tue Jun 30, 2015 1:32 pm

It is not quite impossible, just extremely unlikely.

As to why, it is because the Raspberry Pi is a full small computer, not a hard real time controller.

The SPI setup on the Pi has fairly long latencies for chip select, and the SPI clock is not very fine grained.

This means that you are limited in how often you can sample per second, even if theoretically the ADC is capable of 200ksps.

The other issue is jitter - due to interrupts and other processes, even if you managed 200ksps (which is extremely unlikely) there would be quite a bit of jitter, so instead of one sample every 5us, you would get something more like:

5,7,5,6,10....

microseconds between samples.

On an RPi2 your chances are better, as you could turn off most (other) interrupts to a core, and even bitbang an SPI port, however there will still be some jitter.

Basically, you are trying to use a screwdriver to hammer a nail. It can sort of be done, but it won't do as a good of a job as a hammer.

An I2S audio ADC, sampling at 192khz is a far better choice than an MCP3008, and I believe there are several Pi audio cards (Wulfson?) that can handle that input. Presumably they DMA the I2S audio in to larger buffers,

Or add a DSP like the DSPIC33 series, and have that do the front end processing.

I am also not convinced that sampling at 200ksps will get you the results you want for finding/filtering a 75khz signal.

Nyquest does say you need a minimum of 2 samples, however that is the absolute minimum, and does not get great results. Take a look at what you get if you sample a 75khz sine wave at only 200ksps - look at the actual adc values - and you will get a funny aliased wave, with less than three data points per sine cycle.

The rule of thumb I use for my projects is sample at a minimum 10x the frequency I wish to observe.
Marlboro A$CE wrote:Hi, and thanks for your answers.

I started my tests with a 1608G measurement of computing, it works but I'm unable to listen continuously. I am limited to 500 values per ​​acquisition phase.
When seeing in the datasheet of MCP3008 he could reach 200KHz at 5V I thought it was the right solution.
Not a hope of sampling the MCP3008 at 190KHz
Get an I2S ADC Gold USB microphone.
Why is it impossible? :cry: Can you be a little more precise, it is because of the PI or ADC?
What audio are you Trying to detect? You'll probably do better with a dedicated USB sound card.
I want to sample a signal from a hydrophone at a frequency of 180 ~ 200 kHz in order to detect a signal at 75 kHz (ultrasonic transmitter).
This is the basis of my project.
You will do considerably better if you use my pigpio or the bcm2835 libraries for SPI. They both talk to the hardware directly and do not suffer from the 20k or so transactions per second limit of the Linux driver.
Ok, WiringPI the library does not go through the hardware? Using GPIO and simulating an SPI communication, I reach 4KHz in python and if I use C I get to 180kHz, but the data fluctuate. Some are false. I thought solve my problem using the hardware module.

I'll look pigpio and bookstore bcm2835.
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

Return to “Interfacing (DSI, CSI, I2C, etc.)”