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

An experiment in bit-banging SPI

Mon Mar 03, 2014 12:04 pm

By using bit-banging it is possible to get 12 bit ADC samples from one or more MCP3202s simultaneously. Rates of 25ksps per ADC can be achieved. Conventional SPI only allows one device to talk at a time. By using bit-banging you can share one CLK, MOSI, and SS (slave select) lines between many ADCs but give each its own MISO.

An advantage of bit-banging is that you have tight control of when the samples are taken, in the case given every 40 μs, not as and when the SPI driver gets around to it.

To bit-bang a chain of DMA blocks is used to switch the CLK, MOSI, and SS lines on/off according to the SPI requirements. The DMA blocks also contain gpio reads to capture the data transmitted by the ADC MISO lines. All gpios are read simultaneously (that's the way the Broadcom SOC works) so as many ADCs can be read as can be connected. In my experiment I used 2 ADCs as that is all I have.

The waveforms are constructed by a modified version of the pigpio library. Each waveform is made up of a series of pulses which define its characteristics. Multiple waveforms are generated so that samples can be held in a cyclic buffer in memory (giving enough time to extract the readings). The waveform to capture one sample is given below.

Code: Select all

micro - microseconds from waveform start
On - gpios to switch on
Off - gpios to switch off
G - 1 if time to sample MISO lines
delay - until next pulse

micro On       Off      G delay
    0 00000000 00044000 0 1
    1 00008000 00000000 0 1
    2 00000000 00008000 0 1
    3 00008000 00000000 1 1
    4 00040000 00008000 0 1
    5 00008000 00000000 1 1
    6 00000000 00008000 0 1
    7 00008000 00000000 1 1
    8 00000000 00048000 0 1
    9 00008000 00000000 1 1
   10 00000000 00008000 0 1
   11 00008000 00000000 1 1
   12 00000000 00008000 0 1
   13 00008000 00000000 1 1
   14 00000000 00008000 0 1
   15 00008000 00000000 1 1
   16 00000000 00008000 0 1
   17 00008000 00000000 1 1
   18 00000000 00008000 0 1
   19 00008000 00000000 1 1
   20 00000000 00008000 0 1
   21 00008000 00000000 1 1
   22 00000000 00008000 0 1
   23 00008000 00000000 1 1
   24 00000000 00008000 0 1
   25 00008000 00000000 1 1
   26 00000000 00008000 0 1
   27 00008000 00000000 1 1
   28 00000000 00008000 0 1
   29 00008000 00000000 1 1
   30 00000000 00008000 0 1
   31 00008000 00000000 1 1
   32 00000000 00008000 0 1
   33 00008000 00000000 1 1
   34 00000000 00008000 0 1
   35 00008000 00000000 1 1
   36 00000000 00008000 0 1
   37 00004000 00000000 0 3
During the experiment 2,500,000 samples were taken and written to a log file over a 100 second period. The executing code used about 50% of the CPU to capture the 50ksps. It should only increase slightly for each additional ADC.

Photo of setup.
Zip of captured data.
Miscelleneous plots.


Samples for ADC 1 were generated by a PCF8591. It incorporates a 256 level D/A converter which was used to supply a repeating ramp.
adc-2x-25ksps-02.png
gnuplot: plot 'log' using 1:2
adc-2x-25ksps-02.png (45.62 KiB) Viewed 12753 times
Samples for ADC 2 were generated by twiddling a POT.
adc-2x-25ksps-03.png
gnuplot: plot 'log' using 1:3
adc-2x-25ksps-03.png (38.72 KiB) Viewed 12753 times
One seconds worth of samples
adc-2x-25ksps-05.png
gnuplt: plot [520000:545000] 'log' using 1:2, 'log' using 1:3
adc-2x-25ksps-05.png (63.7 KiB) Viewed 12753 times
Edited to remove broken code link.
Last edited by joan on Wed Jan 27, 2016 11:21 am, edited 1 time in total.

User avatar
Richard-TX
Posts: 1545
Joined: Tue May 28, 2013 3:24 pm
Location: North Texas

Re: An experiment in bit-banging SPI

Mon Mar 03, 2014 1:01 pm

joan wrote:All gpios are read simultaneously (that's the way the Broadcom SOC works)
Are you saying that the GPIOs are read as one word with each bit representing a single GPIO port?
Richard
Doing Unix since 1985.
The 9-25-2013 image of Wheezy can be found at:
http://downloads.raspberrypi.org/raspbian/images/raspbian-2013-09-27/2013-09-25-wheezy-raspbian.zip

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

Re: An experiment in bit-banging SPI

Mon Mar 03, 2014 1:16 pm

Yes.

That is true for any practical use of the Pi. The Pi has 54 gpios, split into a bank of 32 (gpios 0-31) and a bank of 22 (gpios 32-53). All the user accessible gpios are in the first bank and are read as a single 32 bit word. The accessing libraries will normally mask out all but the gpio of interest.

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

Re: An experiment in bit-banging SPI

Mon Mar 03, 2014 1:18 pm

Richard-TX wrote:
joan wrote:All gpios are read simultaneously (that's the way the Broadcom SOC works)
Are you saying that the GPIOs are read as one word with each bit representing a single GPIO port?
Yes see http://www.raspberrypi.org/wp-content/u ... herals.pdf
Page 96 table 6-12 and table 6-13
Just another techie on the net - For GPIO boards see http:///www.facebook.com/pcservicesreading
or http://www.pcserviceselectronics.co.uk/pi/

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

Re: An experiment in bit-banging SPI

Mon Mar 03, 2014 1:24 pm

Looking good Joan, as discussed previously the 'fuzz' is definitely pickup/power rail noise/grounding but that comes with flying wires and breadboard, proves principles.

Great for long term high speed logging, but dont expect to do lots of FFTs at same time and plots in real time :D
Just another techie on the net - For GPIO boards see http:///www.facebook.com/pcservicesreading
or http://www.pcserviceselectronics.co.uk/pi/

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

Re: An experiment in bit-banging SPI

Mon Mar 03, 2014 1:40 pm

techpaul wrote: ...
Great for long term high speed logging, but dont expect to do lots of FFTs at same time and plots in real time :D
Make we wonder why people actually would want high sample rates on the Pi. You can't do anything useful with them once you've got them!

I've had a self-imposed limit of microsecond sampling. I think at some stage I'll try 0.5 micros to see if I can get 50ksps from the MCP3202. That's pretty much as fast as it's rated for at 3.3V.

What do people do with the samples?

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

Re: An experiment in bit-banging SPI

Mon Mar 03, 2014 2:10 pm

joan wrote:
techpaul wrote: ...
Great for long term high speed logging, but dont expect to do lots of FFTs at same time and plots in real time :D
Make we wonder why people actually would want high sample rates on the Pi. You can't do anything useful with them once you've got them!

I've had a self-imposed limit of microsecond sampling. I think at some stage I'll try 0.5 micros to see if I can get 50ksps from the MCP3202. That's pretty much as fast as it's rated for at 3.3V.

What do people do with the samples?
On Pi I would not personally dream of doing those sort of things, usually because the industries that requier them often need other aspects as well.

Seen high frequency sampling for all sorts of things from analysis of metal fatigue, large ceramic production, some people do high speed sampling for analysis of shapes of waveforms and greater details for analysis of materials and effects from wind tunnels to usually short burst events.
Just another techie on the net - For GPIO boards see http:///www.facebook.com/pcservicesreading
or http://www.pcserviceselectronics.co.uk/pi/

CRP99
Posts: 36
Joined: Mon Jan 27, 2014 12:11 am

Re: An experiment in bit-banging SPI

Mon Mar 03, 2014 4:00 pm

joan wrote:Make we wonder why people actually would want high sample rates on the Pi. You can't do anything useful with them once you've got them!
Indeed, that would seem to be the case. :cry:
Having the Pi handle real-time sample data does not seem to be a very practical implementation.

I have had some other thoughts in regards to how I might try to accomplish what it is that I am trying to do, but I will post them back in my prior thread, as any discussion of that here would seemingly be tangential to this thread topic

(http://www.raspberrypi.org/forum/viewto ... 91&t=70167 for future reference / those who do not know what I am referring to)

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

Re: An experiment in bit-banging SPI

Wed Apr 16, 2014 3:04 pm

The latest version of pigpio has the hooks needed to bit-bang SPI.

The interface has changed slightly. I repeated the earlier experiments.
spi-bb-a.png
25ksps - pot+dac overview
spi-bb-a.png (46.02 KiB) Viewed 12254 times
spi-bb-b.png
25ksps - pot+dac detail
spi-bb-b.png (54.81 KiB) Viewed 12254 times
The spikes on the pot line are probably connection glitches as the pot is turned.
spi-bb-c.png
25ksps - pot+dac close-up
spi-bb-c.png (53.91 KiB) Viewed 12254 times
New log zip
New misc

Edited to remove old code which no longer works with current versions of pigpio.
Last edited by joan on Sun Mar 20, 2016 6:32 pm, edited 2 times in total.

User avatar
chrisryall
Posts: 155
Joined: Wed Nov 27, 2013 11:45 am
Location: Wirral UK
Contact: Website

Re: An experiment in bit-banging SPI

Wed Apr 16, 2014 9:33 pm

Clever idea. A robot with say a Pi-brain and up to 4 (should be enough?) "spinal reflex" level arduino/whatever's to control subsystems could read info off them simultaneously and then use a 16 byte single lookup to get the bits into positions 0,8,16,24.

You could then AND in, and bit shift into the 4 bytes of the ARM word all at once (8 times obviously)? Then a mask/shift retrieves the bytes: you have do to split these out at some stage ;) You'd want to set a standard length incoming message format, not too hard.

Same applies I guess to sending commands out, set all four select lines on, again a single wwrite?
Needs a bit of a think .. Efficient it is! Pythonesque? Er, no! :D

matar770
Posts: 12
Joined: Sat Jul 26, 2014 2:17 pm

Re: An experiment in bit-banging SPI

Sun Sep 07, 2014 10:55 am

So with 6 ADCs sampling at 8ksps which translates to 0.125ms sampling period.
with bit banging i would be able to sample those simultaneously with no problems ?

i don't know a thing about the SPI of the Pi.
There are many ways to skin a cat ,,,,

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

Re: An experiment in bit-banging SPI

Sun Sep 07, 2014 11:31 am

Two stats.

First sampling every 40 micros (25 ksps) with 6 ADCs.

$ time sudo ./pispi -s 2500000 >log

real 1m40.545s
user 1m12.020s
sys 0m8.180s

Roughly 20 seconds of spare time in 100 seconds. 20% spare CPU.

Second sampling every 125 micros (8 ksps) with 6 ADCs.

$ time sudo ./pispi -s 2500000 -r 125 >log2

real 5m13.040s
user 1m54.780s
sys 0m20.490s

Roughly 179 seconds of spare time in 313 seconds. 57% spare CPU.

Edited to remove old code which no longer works with current versions of pigpio.
Last edited by joan on Sun Mar 20, 2016 6:34 pm, edited 1 time in total.

ubxm
Posts: 1
Joined: Tue Sep 09, 2014 1:47 pm

Re: An experiment in bit-banging SPI

Tue Sep 09, 2014 1:58 pm

a question, if i may:
i'm trying to understand (but can't figure out) how that while loop (around the getReading(...) function) relates to the 3 byte in the SPI transfer. any pointers for the non-tech-savvy?

cheers

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

Re: An experiment in bit-banging SPI

Tue Sep 09, 2014 8:56 pm

ubxm wrote:a question, if i may:
i'm trying to understand (but can't figure out) how that while loop (around the getReading(...) function) relates to the 3 byte in the SPI transfer. any pointers for the non-tech-savvy?

cheers
I'm not sure I can explain to the non-tech savvy or to the tech-savvy for that matter.

The while loop is trying to extract all the readings made since the last time the loop was entered.

The DMA engine is busy in the background writing out the SPI bits and reading in the 12 words of returned data. The 12 32-bit words each contain 1 bit of information for each attached ADC. The getReading function works out where in memory the DMA engine has stored the words for the current reading and extracts the 12 bits for each attached ADC.

Hopefully the data can be extracted by the userland program faster than the DMA engine can write the data.

kevinrhyne
Posts: 1
Joined: Wed Dec 02, 2015 8:42 am

Re: An experiment in bit-banging SPI

Wed Dec 02, 2015 8:54 am

Currently attempting to use pispi.c as a 11KHz analog signal reader from channel 0 on my MCP3008.

Joan, is there any extra guidance you can offer for this? I'm trying to sample an audio-jack and subsequently build a WAV to be processed elsewhere. You mentioned the solution is not trivial - I assumed as much, since changing the constants did not result in any data coming in by your tool.

This interface must be complete before Thursday, and I'm currently in a coding sprint. Any pointers would be greatly appreciated.

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

Re: An experiment in bit-banging SPI

Wed Dec 02, 2015 9:37 am

kevinrhyne wrote:Currently attempting to use pispi.c as a 11KHz analog signal reader from channel 0 on my MCP3008.

Joan, is there any extra guidance you can offer for this? I'm trying to sample an audio-jack and subsequently build a WAV to be processed elsewhere. You mentioned the solution is not trivial - I assumed as much, since changing the constants did not result in any data coming in by your tool.

This interface must be complete before Thursday, and I'm currently in a coding sprint. Any pointers would be greatly appreciated.
Could you post the code you are using, in particular the pispi.c code. That will need tweaking for the MCP3008. It's not difficult but you do need a clear head, which is not something I always possess.

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

Re: An experiment in bit-banging SPI

Sun Mar 20, 2016 6:56 pm

I have edited earlier posts to remove old code which no longer works with current versions of pigpio.

I have uploaded new examples as follows.

Bit bang multiple MCP3008 10-bit ADC
http://abyz.co.uk/rpi/pigpio/examples.h ... wMCP3008_c
rawMCP3008-3.jpg
rawMCP3008-3.jpg (62.74 KiB) Viewed 5556 times
Bit bang multiple MCP3202 12-bit ADC
http://abyz.co.uk/rpi/pigpio/examples.h ... wMCP3202_c
rawMCP3202-3.png
rawMCP3202-3.png (50.03 KiB) Viewed 5556 times
Bit bang multiple MCP3008 10-bit and MCP3202 12-bit ADC
http://abyz.co.uk/rpi/pigpio/examples.h ... wMCP3XXX_c
rawMCP3XXX-3.jpg
rawMCP3XXX-3.jpg (63.14 KiB) Viewed 5556 times

ultrabizz
Posts: 4
Joined: Wed Mar 16, 2016 2:07 am

Re: An experiment in bit-banging SPI

Wed May 11, 2016 7:41 am

Can you give an example for a 24 bit ADC. I don't really understand the part at the while loop but it seems to be catering for 16 bits of data, so I would need to read 3 full bytes, not two partial.

I assume 24 bits would look as follows.

Code: Select all

val = (rx[i*3]);
Would that be correct?

Also the #define 's at the top. How would they need to look? Below is my guestimate.

Code: Select all

#define ADCS 1    // Number of connected ADCs.
#define BITS 24            // Bits per reading.
#define BX 23               // Bit position of data bit B23.
#define B0 (BX + BITS - 1) // Bit position of data bit B0.
I hope to be reading at 30kHz (33uS) on a Pi3. I am currently using the kernel SPI module but it falls done on the job at that speed. At lower speeds its perfect.
Last edited by ultrabizz on Thu May 12, 2016 12:43 am, edited 1 time in total.

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

Re: An experiment in bit-banging SPI

Wed May 11, 2016 7:53 am

I'll have a look at the defines a little bit later after some other stuff I want to do.

If you are only using one ADC it will be simpler just to use spiOpen and spiXfer.

They should manage more than 30 ksps.

The DMA solution is a maximum of 500 kbps. So to transfer 24 bits means at most 500000/24 or 20.83 ksps. A non-starter for your 30 ksps.

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

Re: An experiment in bit-banging SPI

Thu May 12, 2016 7:33 pm

I didn't take this any further once I realised DMA bit banging wouldn't let you reach your sample rate.

Have you made any progress with alternative methods?

ultrabizz
Posts: 4
Joined: Wed Mar 16, 2016 2:07 am

Re: An experiment in bit-banging SPI

Thu May 12, 2016 9:11 pm

I have not looked further. I am currently using wiringPi's SPI code which just makes calls to the spidev library so I don't think I will be able to coax much more speed out of that. Will the code you referred me to do a better job?
Last edited by ultrabizz on Thu May 12, 2016 10:56 pm, edited 1 time in total.

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

Re: An experiment in bit-banging SPI

Thu May 12, 2016 9:35 pm

ultrabizz wrote: ...
Will the code you referred me to do a better job?
...
It depends on the SPI speed you are using, i.e. how many bits per second your device does, and how many bytes you need to transfer.

Assuming four bytes per transfer.

Times for a Pi B+. Pi Zero/Pi2/Pi3 should be faster.

# 1 Mbps
$ sudo ./spi-speed
sps=24361.5 @ 1000000 bps (1000000/41.0)

# 2 Mbps
$ sudo ./spi-speed 1000000 2000000
sps=47577.6 @ 2000000 bps (1000000/21.0)

# 4 Mbps
$ sudo ./spi-speed 1000000 4000000
sps=89190.0 @ 4000000 bps (1000000/11.2)

# 5 Mbps
$ sudo ./spi-speed 1000000 5000000
sps=108226.7 @ 5000000 bps (1000000/9.2)

Code: Select all

#include <stdio.h>
#include <stdlib.h>

#include <pigpio.h>

/*
   gcc -pthread -o spi-speed spi-speed.c -lpigpio
*/

int main(int argc, char *argv[])
{
   int i;
   int h;
   int loops;
   int speed;
   double start, diff, sps;
   unsigned char buf[4];

   if (argc > 1) loops = atoi(argv[1]);
   else loops = 1000000;

   if (argc > 2) speed = atoi(argv[2]);
   else speed = 1000000;

   if (gpioInitialise() < 0) return 1;

   h = spiOpen(0, speed, 0);

   if (h < 0) return 2;

   start = time_time();

   for (i=0; i<loops; i++)
   {
      buf[0] = 104; // x start_bit single_mode ch1 msbf xxx
      buf[1] = 10;
      buf[2] = 20;
      buf[3] = 30;

      spiXfer(h, buf, buf, 4);
   }

   diff = time_time() - start;

   printf("sps=%.1f @ %d bps (%d/%.1f)\n",
      (double)loops / diff, speed, loops, diff);

   spiClose(h);

   gpioTerminate();

   return 0;
}

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

Who is online

Users browsing this forum: DraDragon and 10 guests