Home    DE    EN
Line Frequency
The Voice of Protons
MCP3201 ADC -> RPI
Proton-Mag I
Proton-Mag II
UV PCB Writer
Lab Power Supply
Light Barrier
Strange Sensor
Solar Controller Hack
Pedal with 270℃ Poti
Misc Stuff
About Myself

A simple way to connect a (relatively) fast MCP3201 ADC to a Raspberry via I2S

Unfortunately Raspberry Pi computers do not have an ADC on board and the typical solutions (e.g. the ADS1115 via I2C) allow only very slow data rates that are sufficient to measure temperature or slow changing voltages, but not signals like an ECG that requires exact hiccup-free sample timing with a sampling frequency in the kHz range. The Raspberry Pi is obviously not designed for higher speed data acquisition. Even connecting an ADC via SPI is not a good solution because of latency issues in between the SPI block transfers.

But there are audio PCM interfaces (such as the HiFiberry) that allow sampling at typical audio rates. Unluckily, these boards are not really designed for measurement purpose, they cannot measure DC for example and the additional audio features (AGC, EQ, Muting, I2C control,...) are making the use difficult to impossible for pure technical measurement projects. But why cant we use the same method to interface with standard ADC converters? When looking at the details things look pretty complex and weird at a first glance. However, the I2S protocol (see Wikipedia I2S) is really simple:

[I2S waveforms]

The Raspberry Pi sends a clock signal and a word select information that decides if the left or right channel bits are clocked in/out. There are even raw drivers available for the Raspberry Pi that allow reading the data in C or Python. Unfortunately the I2S protocol does not look like the serial (often SPI) data "normal" ADCs expect. Here for example the serial communication expected by the MCP3201, a 12-bit 100ksps ADC:

[MCP3201 waveforms]

Having both pictures from above in mind I came up with the idea to use the right channel half of the I2S stream, taking the word select signal (I2S_WS, see figure below), inverting it and feeding it to the MCP3201 as CS signal (ADC_CS). Next a logical and takes the I2S_CLK and the I2S_WS, forming a discontinuous data clock (ADC_CLK) for the MCP3201. That is all! No need for an FPGA! The only drawback is that during half of the I2C sequence (for the other channel, when I2S_WS is low) the MCP3201 is idle, reducing the maximum throughput to 1/2 which means 48ksps (a supported audio rate). However, this is still a useful value for many applications. And in theory a second MCP3201 can be connected in a similar way to allow a two channel system.

The following graph illustrates what happens with the data bits. In fact the MCP3201 is very friendly to connect it to I2S by the method described above because it needs just a shift right by two to get the actual ADC reading from the raw value that will be recieved by the Raspberry:

[I2S and MCP3201 waveforms]

To realize that a single 74xx00 is sufficient as shown in the test circuit below. Note that the MCP3201 is powered by 5V to achieve maximum speed, so a simple level converter formed by R1/R2 for the bitstream to the Raspberry (runs at 3.3V) was required.

[MCP3201 ADC adapter for Raspberry]

A simple prototype was built to prove that everything works as expected in theory. In the background a Raspberry Pi Zero W is connected, the white potentiometer allows to apply a test voltage. These two boards form a nice signal acquisition system that even can be used potential-free without any ground connection when powered from batteries (power bank). Mass storage and wireless LAN is for free, much easier than ADC solutions based on bare metal microcontrollers.

[MCP3201 ADC for Raspberry Prototype]

To make it work a raw I2S driver is needed on the Raspberry. There are several available on the net. There are I2S microphones that require such drivers too, they might be compatible. However, I used the "Rasperry Pi Raw I2S I/O Virtual Codec" at https://github.com/jhol/rpi-raw-i2s-io from GitHub. The installation was pretty straight forward.

There are also lots of programs in C and Python available that capture audio. They all can be used, just the right channel samples need to be taken and shifted two bytes to the right. I have put together a small test program in C for demonstration: raspiAdcTest.c. It reads from the MCP3201 with 48ksps, the samples can be processed as desired. In addition it prints out the actual values once a second on the terminal:

[MCP3201 ADC test console output]

I was surprised that nobody seems to have tried that so far although many are asking if it is possible to connect ADC converters to the Raspberry that can operate well in the kHz range. I think similar approaches can also be applied to connect other ADCs, I am having some (exotic) ADS7807 16 bit converters that also look promising when checking the communication waveforms in the datasheet.

Update 1 - Adding a REF192 to the MCP3201

Because the prototype from above was working fine, I built a better one, adding a reference voltage source. I also added an OpAmp to drive and protect the ADC:

[MCP3201 with REF192]

[MCP3201 with REF192 on better PCB]

Update 2 - Adapting a 16bit ADS7807 to I2S

After the success with the MCP3201 I worked on adapting an ADS7807 to I2S so that it can be connected to a Raspberry. However, this was not so easy compared to the MCP3201 adaption because it the ADS needs an additional signal to trigger a conversation that has to come while CS is low. But even this was possible with just two TTL ICs:

[ADS7807 adapted to I2S for Raspberry]

[ADS7807 on better PCB]

Below the waveforms are shown. The trick is to feed available signals to the flip-flops to achieve prolonging of CS as well as the short R/C pulse after the data transfer. Some delay of the clock is needed so that the first rising edge comes late enough after the falling edge of CS so that the first data bit is available when the I2S_CLK rises (sample point of I2S). The delay is achived by the cascaded inverters, they should be therefore a relatively slow HC-type. With the ADS7807 the maximum sample frequency is 22.050kHz.

[ADS7807 generated waveforms out of I2S]

Bit 14 to 0 will go to bit 15 to 1 in the left channel word, while bit 15 will be fed into bit 0 of the previous right channel word. So an appropriate adjustment will be needed in software.

© 2024 Alexander Mumm