Has anyone used the ADS1256 ADC?

I’ve been fighting with one of these modules I bought off eBay for weeks now and just cannot seem to get sensible communication with it. Has anyone ever managed to get one working in managed code?

I’m on the verge of filing it in B1N before I lose all my hair!!! :wall:

I’ve not used this IC myself but it looks quite simple in regards to the SPI interface. It is command and read which makes it quite easy to use. Your only concern is the delay before you start to read after setting the register tor read.

Can you show some code on how you communicate with the device?

The code as it stands is …


 public delegate void OnMeasurementB(ADS1256 sender, int Measurement);

    public class ADS1256 : GTM.Module
    {
        #region Enumerations

        #region Commands
        // define the command bytes (see table 24 on page 32 in the PDS
        private enum Command : byte
        {
            // Completes SYNC and Exits Standby Mode 
            WAKEUP = 0x00,
            // Read Data     
            RDATA = 0x01,
            // Read Data Continuously       
            RDATAC = 0x03,
            // Stop Read Data Continuously         
            SDATAC = 0x0F,
            // Read from REG rrr      
            RREG = 0x10,
            // Write to REG rrr        
            WREG = 0x50,
            // Offset and Gain Self-Calibration     
            SELFCAL = 0xF0,
            // Offset Self-Calibration    
            SELFOCAL = 0xF1,
            // Gain Self-Calibration      
            SELFGCAL = 0xF2,
            // System Offset Calibration      
            SYSOCAL = 0xF3,
            // System Gain Calibration         
            SYSGCAL = 0xF4,
            // Synchronize the A/D Conversion      
            SYNC = 0xFC,
            // Begin Standby Mode       
            STANDBY = 0xFD,
            // Reset to Power-Up Values  
            RESET = 0xFE,
            // Completes SYNC and Exits Standby Mode   
            WAKEUP2 = 0xFF,
        }

        #endregion

        #region Registers

        // define the ADS1256 registers
        private enum Register : byte
        {
            //  STATUS REGISTER (ADDRESS 00h)
            STATUS = 0x00,
            // Input Multiplexer Control Register (Address 01h)
            MUX = 0x01,
            // A/D Control Register (Address 02h)
            ADCON = 0x02,
            // A/D Data Rate (Address 03h)
            DRATE = 0x03,
            // GPIO Control Register (Address 04H)
            IO = 0x04,
            // Offset Calibration Byte 0, least significant byte (Address 05h)
            OFC0 = 0x05,
            //  Offset Calibration Byte 1 (Address 06h)
            OFC1 = 0x06,
            // Offset Calibration Byte 2, most significant byte (Address 07h)
            OFC2 = 0x07,
            // Full−scale Calibration Byte 0, least significant byte (Address 08h)
            FSC0 = 0x08,
            // Full−scale Calibration Byte 1 (Address 09h)
            FSC1 = 0x09,
            // Full−scale Calibration Byte 2, most significant byte (Address 0Ah)
            FSC2 = 0x0A,
        }

        #endregion

        #region Multiplexer

        public enum MultplexPositive : byte
        {
            AIN0 = (0x0000 << 4),
            AIN1 = (0x0001 << 4),
            AIN2 = (0x0002 << 4),
            AIN3 = (0x0003 << 4),
            AIN4 = (0x0004 << 4),
            AIN5 = (0x0005 << 4),
            AIN6 = (0x0006 << 4),
            AIN7 = (0x0007 << 4),
            AINCOM = (0x0008 << 4),
        }
        // define multiplexer codes
        public enum MultiplexNegative : byte
        {
            AIN0 = 0,
            AIN1,
            AIN2,
            AIN3,
            AIN4,
            AIN5,
            AIN6,
            AIN7,
            AINCOM,
        }

        #endregion

        #region Gains
        // define gain codes
        public enum Gain : byte
        {
            Gain_01 = 0x00,
            Gain_02 = 0x01,
            Gain_04 = 0x02,
            Gain_08 = 0x03,
            Gain_16 = 0x04,
            Gain_32 = 0x05,
            Gain_64 = 0x06,
        }

        #endregion

        #region Sample Rates

        // define sample rates
        public enum SampleRate : byte
        {
            Rate_30000 = 0xF0,
            Rate_15000 = 0xE0,
            Rate_7500 = 0xD0,
            Rate_3750 = 0xC0,
            Rate_2000 = 0xB0,
            Rate_1000 = 0xA1,
            Rate_500 = 0x92,
            Rate_100 = 0x82,
            Rate_60 = 0x72,
            Rate_50 = 0x63,
            Rate_30 = 0x53,
            Rate_25 = 0x43,
            Rate_15 = 0x33,
            Rate_10 = 0x23,
            Rate_5 = 0x13,
            Rate_2Point5 = 0x03,
        }

        #endregion
        #endregion

        private Gain g_Gain = Gain.Gain_01;
        // Used for  reading the data conversion
        byte[] conversionBuffer = new byte[3];

        private byte[] _oneByte = new byte[1];
        private byte[] _threeByte = new byte[3];

        //private byte[] MultiplexChannels = new byte[7];
        private GTI.Spi _spi;
        private GTI.DigitalOutput reset;
        private GTI.DigitalOutput testOP;

        private GTI.InterruptInput dReady;

        private bool _sleepAfterSend = true;
        private int _sleeptime = 1;

        // This will hold the configuration for each of the required channels
        private GTI.SpiConfiguration spiConfig;
        Socket socket;

        public ADS1256(int socketNumber)
        {
            socket = Socket.GetSocket(socketNumber, true, this, null);

            socket.EnsureTypeIsSupported('S', this);

            socket.ReservePin(Socket.Pin.Three, this); // dReady
            socket.ReservePin(Socket.Pin.Four, this);   // Reset
            socket.ReservePin(Socket.Pin.Five, this);   // Spare

            socket.ReservePin(Socket.Pin.Six, this);

            this.dReady = GTI.InterruptInputFactory.Create(socket, Socket.Pin.Three, GTI.GlitchFilterMode.On, GTI.ResistorMode.Disabled, GTI.InterruptMode.FallingEdge, this);

            this.reset = GTI.DigitalOutputFactory.Create(socket, Socket.Pin.Four, true, this);
            this.testOP = GTI.DigitalOutputFactory.Create(socket, Socket.Pin.Five, true, this);

            this.spiConfig = new GTI.SpiConfiguration(false, 0, 0, false, true, 4000);
            _spi = GTI.SpiFactory.Create(this.socket, this.spiConfig, GTI.SpiSharing.Shared, this.socket, Socket.Pin.Six, this);
            Initialise();
            this.dReady.Interrupt += dReady_Interrupt;
        }

        private void Initialise()
        {
            DigitalReset(); // <---- Only used to trigger logic analyser.

             SPIReset(); // <----- Reset the device

            SendCommand(Command.SDATAC);                // Stop Read Data Continuously        
            WriteRegister(Register.STATUS, 0x02);			//WREG - STATUS - Enable buffer
            WriteRegister(Register.ADCON, 0x00);        //WREG - ADCON - default PGA = 1

            WriteRegister(Register.DRATE, (byte)SampleRate.Rate_5);

            WriteRegister(Register.MUX, 0x18);
            SendCommand(Command.SYNC);
            SendCommand(Command.WAKEUP);
        }

        #region Interrupt
        int result;

        void dReady_Interrupt(GTI.InterruptInput sender, bool value)
        {
            WriteRegister(Register.MUX, 0x18);
            SendCommand(Command.SYNC);
            SendCommand(Command.WAKEUP);
            result = ReadData();

            OnMeasurementB(this, result);
        }

        public void GotReading()
        {
            testOP.Write(false);
            testOP.Write(true);

        }
        public event OnMeasurementB MeasurementComplete;
        protected virtual void OnMeasurementB(ADS1256 sender, int record)
        {
            if (MeasurementComplete != null)
                MeasurementComplete(sender, record);
        }

        #endregion

        #region Reset Methods

        public void DigitalReset()
        {
            reset.Write(false);
            reset.Write(true);
        }

        /// <summary>
        /// SPIReset issues a Reset on the SPI Bus to the device.
        /// </summary>
        public void SPIReset()
        {
            SendCommand(Command.RESET);
        }

        #endregion

        #region SPI Communication Methods

        private void SendCommand(Command command)
        {
            _oneByte[0] = (byte)command;
            _spi.Write(_oneByte);
        }

        private void WriteRegister(Register register, byte data)
        {
            _threeByte[0] = (byte)((byte)Command.WREG | (byte)register);
            _threeByte[1] = 0x00;
            _threeByte[2] = data;
            _spi.Write(_threeByte);
        }
        #region Read Methods

        private int ReadData()
        {
            _oneByte[0] = (byte)Command.RDATA;
            _spi.Write(_oneByte);
            //if (_sleepAfterSend) Thread.Sleep(_sleeptime);
            _oneByte[0] = 0x00;
            _spi.WriteRead(_oneByte, conversionBuffer);
            return ((conversionBuffer[0] << 16) & (conversionBuffer[1] << 8) & conversionBuffer[2]);
        }

        #endregion

        #region Write Methods

        private byte[] ReadRegister(Register register, byte number)
        {
            Command command;
            byte[] data = new byte[number];

            command = Command.RREG | (Command)register;
            _oneByte[0] = (byte)command;
            _spi.WriteRead(_oneByte, data);

            return data;
        }
        public int ReadDeviceID()
        {
            byte[] data;
            data = ReadRegister(Register.STATUS, 1);
            return data[0];
        }
        #endregion

        #endregion

    }

Since my original post I have made some headway but it is painfully slow. I discovered that if I use the digital output to reset the module I always end up with 30K sps no matter what. With the Reset pin to tied to 3.3V I am able to almost configure the module. I say ‘almost’ as the data rate adopts the new value after cycling the power sometimes, other times I get a random value less than the 30K.

Measurement values are always returned as 0 but as I have problems with the simple task of setting data rate etc I need to resolve these first. The module has a builtin crystal of 7.68Mhz so the t-values in the datasheet are all in the low microsecond range but it does seem to be a timing issue I think.

Well I ended up getting a new toy in the form of a Saleae Logic Analyser and was up and running in minutes!! There are a few mistakes in the code which have been corrected (And a lot of changes) but the main problems were as follows.


this.spiConfig = new GTI.SpiConfiguration(false, 0, 0, false, true, 4000);

Maximum SPI is fCLKIN / 4 so with a 7.68 Mhz crystal this should be less than 1.92Mhz and sample on the falling edge.


 this.spiConfig = new GTI.SpiConfiguration(false, 0, 0, false, false, 1800);

Another annoying little faux pas was that Commands can only be written when DRDY is low so …


 private void SendCommand(Command command)
        {
            _oneByte[0] = (byte)command;
            _spi.Write(_oneByte);
        }

was changed for …


 private void SendCommand(Command command)
        {
            _oneByte[0] = (byte)command;
            while (dReady.Read())
            { }
            _spi.Write(_oneByte);
        }

And now life is wonderful, my hair is growing back and I have a new favourite toy. ;D

1 Like