Example of how to use the LTC1865 2-Channel SPI 16-bit ADC.

Dependencies:   mbed

Despite much effort I was unable to achieve adequate internal ADC performance on my LPC1768. I had read a lot of material from the mbed community and other sources and tried various solutions, none of which met my requirement for fast ADC sampling and input processing (so, for instance, ruling out averaging over many ADC input values).

I searched for an external ADC meeting the following criteria: - 2 channels - 16-bit resolution - Fast SPI serial I/O - Single 5V supply - Input resolution 0 to 5V - Low cost - DIP or SO package

The LTC1865 fits the bill!

Here is the datasheet: http://cds.linear.com/docs/en/datasheet/18645fb.pdf

The example code shows how to read the ADC in single-ended mode (i.e. each channel reads 0 to 5V).

Please note that my style is 'old hat', as I come from an iRMX and PL/M background of 30 years ago, but it works!

Import programLTC1865_adc

Example of how to use the LTC1865 2-Channel SPI 16-bit ADC.

main.cpp

Committer:
ChrisMabey
Date:
2016-11-09
Revision:
0:778d41341161

File content as of revision 0:778d41341161:

/***************************************************************************************/
/*                                                                                     */
/* Program:         LTC1865_ADC_Example                                                */
/* Author:          Chris Mabey                                                        */
/* Date:            November 2016                                                      */
/* Target Platform: mbed                                                               */
/* Description:     External LTC1865 16-bit ADC example                                */
/* Version:         1v0                                                                */
/*                                                                                     */
/* Notes: After struggling with the internal LPC1768 ADC noise I decided to use an     */
/*        external ADC. My requirements were 2 channels at 16-bit resolution, single   */
/*        5V supply, input range 0 to 5V (Vcc), high sample rate and using a fast SPI  */
/*        clock frequency.                                                             */
/*        I'm very happy with the LTC1855 and as I've received help from the mbed      */
/*        community thought I'd share an example that may be of help to others.        */
/*                                                                                     */
/*        LTC1865 Datasheet: http://cds.linear.com/docs/en/datasheet/18645fb.pdf       */
/*                                                                                     */
/*        Please don't criticise my coding style, it's 'old school' from when I worked */
/*        with Intel iRMX and the PL/M language 30 or so years ago!                    */
/*                                                                                     */
/***************************************************************************************/

#include "mbed.h"

/* ADC (SPI) */
/* ========= */
#define SPI_MOSI_PIN      p5  /* SPI Bus Master Out/Slave In          */
#define SPI_MISO_PIN      p6  /* SPI Bus Master In/Slave Out          */
#define SPI_SCK_PIN       p7  /* SPI Bus Master Clock                 */
#define SPI_CS_ADC_PIN    p8  /* SPI ADC Slave Select                 */

/* The LTC1864 ADC has two input channels */
#define ADC_CHANNEL_0 0
#define ADC_CHANNEL_1 1

/* The LTC1864 conversion cycle begins with the rising edge of CONV.  */
/* After a period equal to tCONV, the conversion is finished.         */
/* The maximum conversion time is 3.2uS, so wait for 4uS as wait_us() */
/* accepts an integer value.                                          */ 
#define ADC_CONVERSION_TIME 4

#define LOW  0
#define HIGH 1


/**********************************************************/
/*                                                        */
/* MBED I/O Ports                                         */
/*                                                        */
/**********************************************************/
DigitalOut ADCcsPin(SPI_CS_ADC_PIN);
SPI spi(SPI_MOSI_PIN, SPI_MISO_PIN, SPI_SCK_PIN);


/* Holds the last ADC conversion channel */
unsigned char previousADCchannel;


/***********************************************************/
/*                                                         */
/* Read_External_ADC                                       */
/*                                                         */
/* Function: Read the latest value from the specified      */
/*           channel of the external LTC1865 ADC.          */
/*                                                         */
/*           Performance: Takes around 15.5uS to execute   */
/*           using 20MHz SPI clock without dummy read for  */
/*           switching channels (measured on NUCLEO-L476RG)*/
/*                                                         */
/* Input Parameters:                                       */
/* unsigned char: the ADC channel (ADC_LP_CHANNEL or       */
/*                ADC_GP_CHANNEL)                          */
/*                                                         */
/* Output Parameters:                                      */
/* unsigned int: the ADC value (range 0 to 65535)          */
/*                                                         */
/***********************************************************/
unsigned int Read_External_ADC(unsigned char channel)
{
    unsigned int adcVal;

    /* If changing channel a dummy read is required as the */
    /* two bits of the input word (SDI) assign the MUX     */
    /* configuration for the next requested conversion.    */
    /*                       ----                          */
    if (channel != previousADCchannel)
    {  
        /* The LTC1865 conversion cycle begins with the rising edge of CONV */
        ADCcsPin = HIGH;

        /* Wait for the conversion to complete */
        wait_us(ADC_CONVERSION_TIME); /* Note: Blocks interrupts! */

        /* Enable the Serial Data Out to allow the data to be shifted out by taking CONV low */
        ADCcsPin = LOW;
        
        /* Send command and read previous selected ADC channel value, whilst */
        /* telling the ADC the next conversion is for the new channel        */
        adcVal = spi.write(0x8000 | (((unsigned int)channel) << 14)); /* Transmit the Mode (Single-ended MUX Mode),     */
                                                                      /* the channel and receive the sixteen bit result */
    
        /* Save the new ADC channel */
        previousADCchannel = channel;        
    }
    /* endif */

    /* The LTC1865 conversion cycle begins with the rising edge of CONV */
    ADCcsPin = HIGH;

    /* Wait for the conversion to complete */
    wait_us(ADC_CONVERSION_TIME);

    /* Enable the Serial Data Out to allow the data to be shifted out by taking CONV low */
    ADCcsPin = LOW;

    /* Send command and read previous selected ADC channel value, whilst */        
    /* telling the ADC the next conversion is for the same channel       */
    adcVal = spi.write(0x8000 | (((unsigned int)channel) << 14)); /* Transmit the Mode (Single-ended MUX Mode),     */
                                                                  /* the channel and receive the sixteen bit result */

    return(adcVal);  /* Return the 16-bit ADC value */
}


int main()
{
    /**********************************************************/
    /*                                                        */
    /* Initialise the SPI interface to the external ADC       */
    /*                                                        */
    /**********************************************************/
    spi.format(16,1);        /* 16-bit data, Mode 1 */
    spi.frequency(20000000); /* 20MHz clock rate    */

    ADCcsPin = LOW; /* Deselect the ADC by setting chip select low */

    /* Perform a dummy read to initialise the ADC conversion channel to ADC_CHANNEL_0 */
    Read_External_ADC(ADC_CHANNEL_0);

    printf("\n\rLTC1865 External ADC Example\n\r");

    while(1)
    {
        printf("Channel 0 = %5u   ", Read_External_ADC(ADC_CHANNEL_0));

        wait(0.5f); /* 0.5s */

        printf("Channel 1 = %5u\n\r", Read_External_ADC(ADC_CHANNEL_1));        
    }
    /* end while */
}