Analog In/Out

The Gertboard has an on-board Digital to Analog (DAC) converter and an Analog to Digital (ADC) converters. These are connected via the SPI bus back to the Raspberry Pi host.

Each of the DAC and ADC chips has 2 channels.

The DAC has a resolution of 8 bits and produces an output voltage between 0 and 2.047 volts, the ADC has a resolution of 10 bits and can take an input voltage between 0 and 3.3 volts.

Part of the wiringPi library includes code to setup and drive these chips in an easy to use manner. Get wiringPi here.

To use in a C/C++ program, first you need to make sure that the 5 SPI jumpers are present on the Gertboard (there are 7 in total, 5 for the SPI, 2 to connect the serial to the ATmega) – the photo below shows all 7 jumpers in-place.

Jumpers on the Gertboard

Jumpers on the Gertboard

In your C/C++ program you also need to:

#include <gertboard.h>

and compile with

cc -o myProg myprog.c -lwiringPi

The following functions are available:

  • int gertboardSPISetup (void)

This must be called to initialise the SPI bus to communicate with the Gertboards ADC and DAC chips. If the return value is < 0 then an error occurred and errno will be set appropriately.

  • int gertboardAnalogRead (int channel)

This returns a value from 0 to 1023 representing the value on the supplied channel (0 or 1). To convert this to a voltage, use the following formula:

vIn = value * 3.3 / 1023

  • int gertboardAnalogWrite (int channel, int value)

This outputs the supplied value (0-255) to the given channel (0 or 1). The output voltage is:

vOut = value / 255 * 2.047

or to find the value for a given voltage:

value = vOut / 2.047 * 255

The sample program in the wiringPi examples directory; gertboard.c is designed to output a sine wave on DAC channel 0, then reflect whatever comes into ADC channel 0 to DAC channel 1. So if you loop DAC output 0 to ADC input 1 while running this program and connect an oscilloscope to the DAC outputs, then you should get this:

Demonstration of the Gertboards Analog adapters

Demonstration of the Gertboards Analog adapters

The cyan trace is the output from DAC 0 (0 to 2.047 volts), and the yellow trace is the output from DAC 1 – which is smaller as the 2 volt, 8 bit output is scaled.



Analog In/Out — 13 Comments

    • Not 100% sure what you’re after, however..

      The DAC can create outputs as fast as you can send data to it – the max. SPI clock is 25MHz, so that means 16MHz for us. It takes 2 bytes to send a sample to it, so in-theory you can send 1.5M Bytes/sec, or about 750,000 samples/sec. What gets in the way is the Linux kernel which will reduce that by at least half. If you want to create buffers full of a waveform, then you can do that and send it much faster (without the intervening gap every 2 bytes) but you need to call the underlying code that the functions I wrote call, or drive the SPI device directly.

      I set the clock to 1MHz for no reason than to make it the same as the ADC, although I think both devices can have different clock speeds.

      For reading the ADC, it can provide a 10-bit sample for every 3 bytes sent to it, and the clock in my code is set to 1MHz, so that’s about 100,000 bytes/sec or 30,000 samples/sec. Again, the kernel will add overhead to that and reduce the effective sample rate somewhat, but you could construct a long buffer of commands to stream the samples faster. The actual chip can run with a clock from 1MHz to 3MHz (The Pi can not do 3MHz, so only 1 or 2 MHz) however it’s dependant on the voltage and 2MHz is slightly out of spec. for 3.3v.

      If you look at the scope output picture, the frequency generated is about 26Hz…. That’s from a 200 element deep buffer, so the code is outputting 200 * 26 = 5200 samples/sec. however that’s doing 2 outputs and a read, so the fastest you’ll achieve is in the order of 3 times that, or 16,000 outputs/sec. and slightly less reads, as it needs 3 bytes to do a read.

      If you want to do your own timing and don’t have a Gertboard yet, then the code will still run – there’s no handshaking over the SPI bus, so it won’t stall or lock-up.

      Hope this helps!


  1. In your last paragraph, you mention DAC0 for the second scaled output. I think this should say DAC1. How that helps clarify.

    Great site!

  2. I have prototyped a circuit that is the same as the Gertboard DAC, but used the MCP4822 in place of the MCP4802. I am trying to drive it with the help of wiringPi, but I am not getting the full resolution. If I send 255 I get 2.04 volts out. Could wiringPi be adapted to make the full resolution possible? I have tried reading the source but my C is weak. 🙁

    Thanks for a great resource in wiringPi and this website!
    All the best,

    • Th Gertboard chip is driven at 3.3v, so if your is also driven at 3.3v then setting the internal gain selection bit won’t achieve what you need – as it can’t generate 4.096 volts from 3.3 volts.

      If you’re running it at 5v then you can set this bit and get 0-4.095 volts output.

      Changing the code is easy – chanBits would be 0x10 or 0x90 instead of 0x30 and 0xB0 respectively, then:

      chanBits |= ((value >> 4) & 0x0F) ;
      dataBits = ((value << 4) & 0xF0) ; get changed to chanBits |= ((value >> 8) & 0x0F) ;
      dataBits = value & 0xFF ;

      untested, but it might work… And remember that full scale will be 4095 not 255.


      • I have setup just like the Gertboard, so I only have the 2.048 volt option.

        I think this is the change I need to make.
        chanBits |= ((value >> 8) & 0x0F) ;
        dataBits = (value & 0xFF) ;

        Will test that tomorrow. If it works, then I have learnt a little this evening.


  3. I want to read 5V instead of 3.3V on my ADC. Is it possible ?
    Thank you !


    • Not easilly. The chips are designed to only work from 0 to 3.3v. You could use a resistor voltage divider though, but you’ll lose a little accuracy. If you were to use (e.g.) a 3.3K and 2.2K resistor divider, then 5v in would come out as

      5 * 3.3 / ( 2.2 + 3.3) = 3v

      so you can adjust the calculations to suit.


  4. I’d like to record 4 seconds of adc data and write it to a file on the thumb drive that I installed, but I haven’t been able to find info on creating and writing files.

    • man fopen
      man fwrite
      man fclose

      biggest issue you might face is the speed of the ADC -it’s fast enough the but SPI bus will limit you to just over 8000 samples/sec.


      • 1000 samples / sec is sufficient. I’m recording seismic data max 50Hz.
        Can the file be written as fast as the SPI bus can deliver it or is it buffered?
        By the way you are an absolutely invaluable source of knowledge and advice. And baked goods apparently.
        Thanks so much. Gowan