This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

CCS/CC2640R2F: Multiple ADCs example

Part Number: CC2640R2F
Other Parts Discussed in Thread: CC2640, MSP432E401Y

Tool/software: Code Composer Studio

Hi, 

There is an 'adcsinglechannel' example on CCS, do you have one for multiple ADC channels, such as 4 to 6 ADCs?

I just need to use this CC2640R2F to take 4 inputs, and then prints data through UART.

If this launchpad doesn't have this example, please let me know which other launchpad has this multi-ADC channels example.

Thanks. 

  • Please see the example adcbufmultichannel in the MSP432P4 SDK, dev.ti.com/.../node .

    Regards,
    Chris
  • Hi Chris, 

    Thanks for the reply.

    This example has 2 ADC channels, I need to use total of 4 ADC channels.

    I see there are 8 more Analog input pins beside A1 & A0 that are used for this example. 

    However, there are only 2 internal ADC based on the Datasheet (if I read it correctly), I have 4 analog input signals. 

    Is there a good way to read all 4 analog input signals on this board without using external ADCs?

    Please advise, and thanks.

    TH

  • There is only one 12-bit SAR ADC available for the application.  In the block diagram, there are two ADCs shown in the RF Core, but those are not accessible outside of the chip.  The SAR ADC is found in the sensor controller block and can be used to sequentially scan multiple channels.  If you need simultaneous sampling, then you would need to use an external ADC(s).  

    My thinking was that you could take the existing example and update the continuousConversion to an array of ADCBuf_Conversion

    ADCBuf_Conversion continuousConversion[4];

    and the definitions would change for each channel

    continuousConversion[0].adcChannel = Board_ADCBUF0CHANNEL0;
    continuousConversion[1].adcChannel = Board_ADCBUF0CHANNEL1;
    continuousConversion[2].adcChannel = Board_ADCBUF0CHANNEL2;
    continuousConversion[3].adcChannel = Board_ADCBUF0CHANNEL3;

    Additionally, you will need to update the other conversion parameters and define the channel 2 and 3 since the example only defines 0 and 1.

    Hopefully that makes sense.  Again, you can refer to the previous example which has 2 channels for comparison.

    Regards,

    Chris

  • Hi Chris, 

    I took your earlier advice that to use MSP-EXP432P401R launchPad, so I will contiune to use this one instead of CC2640 one.

    This MSP-EXP432 has more internal ADCs, right?

    I have modified the 'adcbufcontinuous'_MSP_EXP432..' example according to your suggestions, I wonder where can I assign external pins for all four analog inputs?

    And is there anything else that I need to modify on this example?

    Thanks,

    TH

  • TH,

       In the SimpleLink Family of MCUs only one device has multiple ADCs.  This would be the MSP432E401Y, which has two.  In all of the other devices there is at least one ADC and it is multiplexed to several channels. The TI Drivers software examples found in resource explorer are intended to be device agnostic, so you should be able to run the same software across multiple platforms.

        You should modify the following for you application:

    (1) Board.h - here you will define the ADC channels, I would recommend simply reusing the naming convention there Board_ADCBUF0CHANNEL0 - 3.  In the CC2640 example 2-3 are not present and would need to be added. 

    (2) Update the enumeration in MSP_EXP432P401R.h ( or CC2640R2_LAUNCHXL.h) to the naming convention or simply reuse

    (3) Update MSP_EXP432P401R.c ( or CC2640R2_LAUNCHXL.c)  Please note that the harware attributes are setup differently.  In the MSP you will see the parameter .adcPin which is set to the pin/channel definition.  In the CC2640, all of the definitions are provided.

    (4) Update the application to accomidate the additional channels.  It would be an expansion of what is found in the MSP adcbufmultichannel example.  

        /* Configure the conversion struct for two channels on same sequencer */
        continuousConversion[0].arg = NULL;
        continuousConversion[0].adcChannel = Board_ADCBUF0CHANNEL0;
        continuousConversion[0].sampleBuffer = sampleBufferOne;
        continuousConversion[0].sampleBufferTwo = sampleBufferTwo;
        continuousConversion[0].samplesRequestedCount = ADCBUFFERSIZE;
    
        continuousConversion[1].arg = NULL;
        continuousConversion[1].adcChannel = Board_ADCBUF0CHANNEL1;
        continuousConversion[1].sampleBuffer = sampleBufferThree;
        continuousConversion[1].sampleBufferTwo = sampleBufferFour;
        continuousConversion[1].samplesRequestedCount = ADCBUFFERSIZE;
    
        if (!adcBuf){
            /* AdcBuf did not open correctly. */
            while(1);
        }
    
        /* Start converting sequencer 0. */
        if (ADCBuf_convert(adcBuf, continuousConversion, 2) !=
            ADCBuf_STATUS_SUCCESS) {
            /* Did not start conversion process correctly. */
            while(1);
        }

     Regards,

    Chris

  • HI Chris, 

    I did those modification to CC2640 launchPad as below.

    /* Configure the conversion struct */
    continuousConversion[0].arg = NULL;
    continuousConversion[0].adcChannel = Board_ADCBUF0CHANNEL0;
    continuousConversion[0].sampleBuffer = sampleBufferOne;
    continuousConversion[0].sampleBufferTwo = sampleBufferTwo;
    continuousConversion[0].samplesRequestedCount = ADCBUFFERSIZE;

    continuousConversion[1].arg = NULL;
    continuousConversion[1].adcChannel = Board_ADCBUF0CHANNEL1;
    continuousConversion[1].sampleBuffer = sampleBufferThree;                     
    continuousConversion[1].sampleBufferTwo = sampleBufferFour;
    continuousConversion[1].samplesRequestedCount = ADCBUFFERSIZE;

    continuousConversion[2].arg = NULL;
    continuousConversion[2].adcChannel = Board_ADCBUF0CHANNEL2;
    continuousConversion[2].sampleBuffer = sampleBufferFive;
    continuousConversion[2].sampleBufferTwo = sampleBufferSix;
    continuousConversion[2].samplesRequestedCount = ADCBUFFERSIZE;

    continuousConversion[3].arg = NULL;
    continuousConversion[3].adcChannel = Board_ADCBUF0CHANNEL3;
    continuousConversion[3].sampleBuffer = sampleBufferSeven;
    continuousConversion[3].sampleBufferTwo = sampleBufferEight;
    continuousConversion[3].samplesRequestedCount = ADCBUFFERSIZE;

    if (!adcBuf){
    /* ADCBuf failed to open. */
    while(1);
    }

    /* Start converting. */
    if (ADCBuf_convert(adcBuf, &continuousConversion, 4) !=
    ADCBuf_STATUS_SUCCESS) {
    /* Did not start conversion process correctly. */
    while(1);
    }

    However, I'm not sure where to assign the pins for those extra channels.

    I guess that I'm not sure which part takes care of pin assignments.

    In the 'CC2640R2_LAUNCHXL.h', there is pin assignments, but how do I select actual DIO# for specific ADCBUF0CHANNEL?

    /* Analog Capable DIOs */
    #define CC2640R2_LAUNCHXL_DIO23_ANALOG IOID_23
    #define CC2640R2_LAUNCHXL_DIO24_ANALOG IOID_24
    #define CC2640R2_LAUNCHXL_DIO25_ANALOG IOID_25
    #define CC2640R2_LAUNCHXL_DIO26_ANALOG IOID_26
    #define CC2640R2_LAUNCHXL_DIO27_ANALOG IOID_27
    #define CC2640R2_LAUNCHXL_DIO28_ANALOG IOID_28
    #define CC2640R2_LAUNCHXL_DIO29_ANALOG IOID_29
    #define CC2640R2_LAUNCHXL_DIO30_ANALOG IOID_30

    typedef enum CC2640R2_LAUNCHXL_ADCBuf0ChannelName {
    CC2640R2_LAUNCHXL_ADCBUF0CHANNEL0 = 0,
    CC2640R2_LAUNCHXL_ADCBUF0CHANNEL1,
    CC2640R2_LAUNCHXL_ADCBUF0CHANNEL2,
    CC2640R2_LAUNCHXL_ADCBUF0CHANNEL3,

    Thanks!

  • Hi Chris,

    There is another error that I'm getting after I updated the line of code below:
    /* Start converting. */
    if (ADCBuf_convert(adcBuf, &continuousConversion, 4) !=

    The error is {#169-D argument of type "ADCBuf_Conversion (*)[4]" is incompatible with parameter of type "ADCBuf_Conversion *"}
    Please advise and thanks.
  • Hello,

     You should remove the '&' in the parameters.

        /* Start converting sequencer 0. */
        if (ADCBuf_convert(adcBuf, continuousConversion, 2) !=
            ADCBuf_STATUS_SUCCESS) {
            /* Did not start conversion process correctly. */
            while(1);
        }

    To your earlier question the digital IO is used in the adcbuf objects in CC2640R2_LAUNCHXL.c.

    /*
     *  This table converts a virtual adc channel into a dio and internal analogue
     *  input signal. This table is necessary for the functioning of the adcBuf
     *  driver. Comment out unused entries to save flash. Dio and internal signal
     *  pairs are hardwired. Do not remap them in the table. You may reorder entire
     *  entries. The mapping of dio and internal signals is package dependent.
     */
    const ADCBufCC26XX_AdcChannelLutEntry ADCBufCC26XX_adcChannelLut[CC2640R2_LAUNCHXL_ADCBUF0CHANNELCOUNT] = {
        {CC2640R2_LAUNCHXL_DIO23_ANALOG, ADC_COMPB_IN_AUXIO7},
        {CC2640R2_LAUNCHXL_DIO24_ANALOG, ADC_COMPB_IN_AUXIO6},
        {CC2640R2_LAUNCHXL_DIO25_ANALOG, ADC_COMPB_IN_AUXIO5},
        {CC2640R2_LAUNCHXL_DIO26_ANALOG, ADC_COMPB_IN_AUXIO4},
        {CC2640R2_LAUNCHXL_DIO27_ANALOG, ADC_COMPB_IN_AUXIO3},
        {CC2640R2_LAUNCHXL_DIO28_ANALOG, ADC_COMPB_IN_AUXIO2},
        {CC2640R2_LAUNCHXL_DIO29_ANALOG, ADC_COMPB_IN_AUXIO1},
        {CC2640R2_LAUNCHXL_DIO30_ANALOG, ADC_COMPB_IN_AUXIO0},
        {PIN_UNASSIGNED, ADC_COMPB_IN_VDDS},
        {PIN_UNASSIGNED, ADC_COMPB_IN_DCOUPL},
        {PIN_UNASSIGNED, ADC_COMPB_IN_VSS},
    };

    Please note that these are referenced in CC2640R2_LAUNCHXL.h.

    /*!
     *  @def    CC2640R2_LAUNCHXL_ADCBuf0SourceName
     *  @brief  Enum of ADCBuf channels
     */
    typedef enum CC2640R2_LAUNCHXL_ADCBuf0ChannelName {
        CC2640R2_LAUNCHXL_ADCBUF0CHANNEL0 = 0,
        CC2640R2_LAUNCHXL_ADCBUF0CHANNEL1,
        CC2640R2_LAUNCHXL_ADCBUF0CHANNEL2,
        CC2640R2_LAUNCHXL_ADCBUF0CHANNEL3,
        CC2640R2_LAUNCHXL_ADCBUF0CHANNEL4,
        CC2640R2_LAUNCHXL_ADCBUF0CHANNEL5,
        CC2640R2_LAUNCHXL_ADCBUF0CHANNEL6,
        CC2640R2_LAUNCHXL_ADCBUF0CHANNEL7,
        CC2640R2_LAUNCHXL_ADCBUF0CHANNELVDDS,
        CC2640R2_LAUNCHXL_ADCBUF0CHANNELDCOUPL,
        CC2640R2_LAUNCHXL_ADCBUF0CHANNELVSS,
    
        CC2640R2_LAUNCHXL_ADCBUF0CHANNELCOUNT
    } CC2640R2_LAUNCHXL_ADCBuf0ChannelName;

    Regards,

    Chris

  • HI Chris, 

    The error is gone, thanks.

    Sorry that I'm still confused on the pin assignment. 

    the part that you talked about in the last reply, but I'm not sure on how to assign them for each ADCBUF0CHANNEL# below.

    Board_ADCBUF0CHANNEL0;

    Board_ADCBUF0CHANNEL1;

    Board_ADCBUF0CHANNEL2;

    Board_ADCBUF0CHANNEL3;

    Can I assign those 4x ADCBUF0CHANNEL# to those physical pins below? 

    If not, are those physical pins pre-assigned to any of those ADCBUF0CHANNEL# ?

      {CC2640R2_LAUNCHXL_DIO25_ANALOG, ADC_COMPB_IN_AUXIO5},
      {CC2640R2_LAUNCHXL_DIO26_ANALOG, ADC_COMPB_IN_AUXIO4},
      {CC2640R2_LAUNCHXL_DIO27_ANALOG, ADC_COMPB_IN_AUXIO3},
      {CC2640R2_LAUNCHXL_DIO28_ANALOG, ADC_COMPB_IN_AUXIO2},

    Thanks!

  • I was thinking that the definitions in the Board.h file would look like this:

    #define Board_ADCBUF0           CC2640R2_LAUNCHXL_ADCBUF0
    #define Board_ADCBUF0CHANNEL0   CC2640R2_LAUNCHXL_ADCBUF0CHANNEL0    //  DIO23
    #define Board_ADCBUF0CHANNEL1   CC2640R2_LAUNCHXL_ADCBUF0CHANNEL1    //  DIO24
    #define Board_ADCBUF0CHANNEL2   CC2640R2_LAUNCHXL_ADCBUF0CHANNEL2    //  DIO25
    #define Board_ADCBUF0CHANNEL3   CC2640R2_LAUNCHXL_ADCBUF0CHANNEL3    //  DIO26
    #define Board_ADCBUF0CHANNEL4   CC2640R2_LAUNCHXL_ADCBUF0CHANNEL4    //  DIO27
    #define Board_ADCBUF0CHANNEL5   CC2640R2_LAUNCHXL_ADCBUF0CHANNEL5    //  DIO28
    #define Board_ADCBUF0CHANNEL6   CC2640R2_LAUNCHXL_ADCBUF0CHANNEL6    //  DIO29

    Since the definitions are already in place in the CC2640R2_LAUNCHXL.c/.h you would only need to reference the correct Board_ definition, channels 2-5, in the application file.

        /* Configure the conversion struct */
        continuousConversion[0].arg = NULL;
        continuousConversion[0].adcChannel = Board_ADCBUF0CHANNEL2;
        continuousConversion[0].sampleBuffer = sampleBuffer0Primary;
        continuousConversion[0].sampleBufferTwo = sampleBuffer0Alternate;
        continuousConversion[0].samplesRequestedCount = ADCBUFFERSIZE;
    
        continuousConversion[1].arg = NULL;
        continuousConversion[1].adcChannel = Board_ADCBUF0CHANNEL3;
        continuousConversion[1].sampleBuffer = sampleBuffer1Primary;
        continuousConversion[1].sampleBufferTwo = sampleBuffer1Alternate;
        continuousConversion[1].samplesRequestedCount = ADCBUFFERSIZE;
    
        continuousConversion[2].arg = NULL;
        continuousConversion[2].adcChannel = Board_ADCBUF0CHANNEL4;
        continuousConversion[2].sampleBuffer = sampleBuffer2Primary;
        continuousConversion[2].sampleBufferTwo = sampleBuffer2Alternate;
        continuousConversion[2].samplesRequestedCount = ADCBUFFERSIZE;
    
        continuousConversion[3].arg = NULL;
        continuousConversion[3].adcChannel = Board_ADCBUF0CHANNEL5;
        continuousConversion[3].sampleBuffer = sampleBuffer3Primary;
        continuousConversion[3].sampleBufferTwo = sampleBuffer3Alternate;
        continuousConversion[3].samplesRequestedCount = ADCBUFFERSIZE;
    
        if (adcBuf == NULL){
            /* ADCBuf failed to open. */
            while(1);
        }
    
        /* Start converting. */
        if (ADCBuf_convert(adcBuf, continuousConversion, 4) !=
            ADCBuf_STATUS_SUCCESS) {
            /* Did not start conversion process correctly. */
            while(1);
        }

    Regards,

    Chris

  • Okay, I see.
    I have modified the code, and there is no error like I was doing earlier.
    The reason that I asked about the pin assignment is that I couldn't see the reading through Putty when I send signal to those assigned pins.
    Even after I modified the code from your last reply, I can only see the reading from DIO27, not from other pins.
    Please advise.
    Thanks.
  • Hi Chris,

    I have modified the program, and the error is gone.
    However, when I put input signal on the pyhsical pins below and monitor it with PuTTY , only DIO27 see signal.
    #define Board_ADCBUF0CHANNEL2 CC2640R2_LAUNCHXL_ADCBUF0CHANNEL2 // DIO25
    #define Board_ADCBUF0CHANNEL3 CC2640R2_LAUNCHXL_ADCBUF0CHANNEL3 // DIO26
    #define Board_ADCBUF0CHANNEL4 CC2640R2_LAUNCHXL_ADCBUF0CHANNEL4 // DIO27
    #define Board_ADCBUF0CHANNEL5 CC2640R2_LAUNCHXL_ADCBUF0CHANNEL5 // DIO28

    I wonder what can go wrong here?
    Please advise.
    Thanks.
  • I think the example needs to be re-thought. I am also seeing only one channel but it is DIO25. The call back is happening after the buffer with DIO25 information is full. Unfortunately while the data is being transmitted via uart the buffers for the other three channels are also completed. I think the callback should be re-written so that after all four channels are measured an output is made while the next set of data is being collected. For testing purposes can you change the callback to only printout information when the last (fourth) channel is complete? I will look into it from my side.

    Chris
  • Hi Chris, 

    Yes, we can change the callback to only printout information when the last (fourth) channel is complete.

    Does TI have any existing example on other launchpad that can do this? I am assuming this is a very common application. 

    If not, let's stick with those launchpads. 

    Thanks!

  • I believe that I have discovered the issue.  If you look at the actual driver, ADCBufCC26XX.c the channel count information is not used.

    /*
     * ======== ADCBufCC26XX_convert ========
     */
    int_fast16_t ADCBufCC26XX_convert(ADCBuf_Handle handle, ADCBuf_Conversion conversions[],  uint_fast8_t channelCount) {
        uint32_t                        key;
        ADCBufCC26XX_Object             *object;
        ADCBufCC26XX_HWAttrs const      *hwAttrs;
        PIN_Config                      adcPinTable[2];
        uint8_t i = 0;
    
        DebugP_assert(handle);
    
        /* Get the pointer to the object */
        object = handle->object;
        hwAttrs = handle->hwAttrs;
    
        DebugP_assert(channelCount == 1);

    I am afraid that I am more familiar/used to the MSP432 driver which uses the channel count.  

    /*
     *  ======== primeConvert ========
     */
    static int_fast16_t primeConvert(ADCBuf_Handle handle,
            ADCBufMSP432_HWAttrs const *hwAttrs, ADCBuf_Conversion *conversions,
            uint_fast8_t channelCount)
    {
        ADCBufMSP432_Object  *object = handle->object;
        uint32_t channelInt;
        uint32_t memory = ADC_MEM0;
        uint_fast8_t i = 0;
    
        /* Store the conversions struct array into object */
        object->conversions = conversions;
        /* Store the channel count into object */
        object->channelCount = channelCount;
    
        /* For multiple channels sampling, ref source and sampling duration should be same */
        uint32_t refSource =
            hwAttrs->channelSetting[conversions[0].adcChannel].refSource;
    
        for (i = 0; i < channelCount; i++){
            if (refSource !=
                hwAttrs->channelSetting[conversions[i].adcChannel].refSource) {
                return (ADCBuf_STATUS_ERROR);
            }
        }

    This means that at the driver level multiple channels are not supported with the CC2640R2F.  I will need to investigate further to determine why this is.

    Regards,

    Chris

  • I have MSP-EXP432P401R launchPad, so we can use it instead of CC2640.

    And I have tried to use MSP-EXP432P401R launchPad too.

    In "Board.h" file, I added those pin definations below, and I'm using P4.7, P4.5, P4.0 and P6.1 for 4x analog inputs:

    #define Board_ADCBUF0CHANNEL6 MSP_EXP432P401R_ADCBUF0CHANNEL6 // P4.7
    #define Board_ADCBUF0CHANNEL8 MSP_EXP432P401R_ADCBUF0CHANNEL8 // P4.5
    #define Board_ADCBUF0CHANNEL13 MSP_EXP432P401R_ADCBUF0CHANNEL13 // P4.0
    #define Board_ADCBUF0CHANNEL14 MSP_EXP432P401R_ADCBUF0CHANNEL14 // P6.1

    In "MSP_EXP432P401R.h" file, I added:

    typedef enum MSP_EXP432P401R_ADCBuf0ChannelName {
    MSP_EXP432P401R_ADCBUF0CHANNEL0 = 0,
    MSP_EXP432P401R_ADCBUF0CHANNEL1,
    MSP_EXP432P401R_ADCBUF0CHANNEL6,
    MSP_EXP432P401R_ADCBUF0CHANNEL8,
    MSP_EXP432P401R_ADCBUF0CHANNEL13,
    MSP_EXP432P401R_ADCBUF0CHANNEL14,

    In "MSP_EXP432P401R.c" file, I added:

    ADCBufMSP432_Channels adcBuf0MSP432Channels[MSP_EXP432P401R_ADCBUF0CHANNELCOUNT] = {
    {
    .adcPin = ADCBufMSP432_P5_5_A0,
    .refSource = ADCBufMSP432_VREFPOS_AVCC_VREFNEG_VSS,
    .refVoltage = 3300000,
    .adcInputMode = ADCBufMSP432_SINGLE_ENDED,
    .adcDifferentialPin = ADCBufMSP432_PIN_NONE,
    .adcInternalSource = ADCBufMSP432_INTERNAL_SOURCE_MODE_OFF
    },
    {
    .adcPin = ADCBufMSP432_P5_4_A1,
    .refSource = ADCBufMSP432_VREFPOS_INTBUF_VREFNEG_VSS,
    .refVoltage = 2500000,
    .adcInputMode = ADCBufMSP432_SINGLE_ENDED,
    .adcDifferentialPin = ADCBufMSP432_PIN_NONE,
    .adcInternalSource = ADCBufMSP432_INTERNAL_SOURCE_MODE_OFF
    },
    {
    .adcPin = ADCBufMSP432_P4_7_A6,
    .refSource = ADCBufMSP432_VREFPOS_INTBUF_VREFNEG_VSS,
    .refVoltage = 3300000,
    .adcInputMode = ADCBufMSP432_SINGLE_ENDED,
    .adcDifferentialPin = ADCBufMSP432_PIN_NONE,
    .adcInternalSource = ADCBufMSP432_INTERNAL_SOURCE_MODE_OFF
    },
    {
    .adcPin = ADCBufMSP432_P4_5_A8,
    .refSource = ADCBufMSP432_VREFPOS_INTBUF_VREFNEG_VSS,
    .refVoltage = 3300000,
    .adcInputMode = ADCBufMSP432_SINGLE_ENDED,
    .adcDifferentialPin = ADCBufMSP432_PIN_NONE,
    .adcInternalSource = ADCBufMSP432_INTERNAL_SOURCE_MODE_OFF
    },
    {
    .adcPin = ADCBufMSP432_P4_0_A13,
    .refSource = ADCBufMSP432_VREFPOS_INTBUF_VREFNEG_VSS,
    .refVoltage = 3300000,
    .adcInputMode = ADCBufMSP432_SINGLE_ENDED,
    .adcDifferentialPin = ADCBufMSP432_PIN_NONE,
    .adcInternalSource = ADCBufMSP432_INTERNAL_SOURCE_MODE_OFF
    },
    {
    .adcPin = ADCBufMSP432_P6_1_A14,
    .refSource = ADCBufMSP432_VREFPOS_INTBUF_VREFNEG_VSS,
    .refVoltage = 3300000,
    .adcInputMode = ADCBufMSP432_SINGLE_ENDED,
    .adcDifferentialPin = ADCBufMSP432_PIN_NONE,
    .adcInternalSource = ADCBufMSP432_INTERNAL_SOURCE_MODE_OFF
    },
    };

    In "adcBufContinuousSampling.c" file, I added:

    uint16_t sampleBufferOne[ADCBUFFERSIZE];
    uint16_t sampleBufferTwo[ADCBUFFERSIZE];
    uint16_t sampleBufferThree[ADCBUFFERSIZE];
    uint16_t sampleBufferFour[ADCBUFFERSIZE];
    uint16_t sampleBufferFive[ADCBUFFERSIZE];
    uint16_t sampleBufferSix[ADCBUFFERSIZE];
    uint16_t sampleBufferSeven[ADCBUFFERSIZE];
    uint16_t sampleBufferEight[ADCBUFFERSIZE];

    * ======== mainThread (also modified here) ========
    */
    void *mainThread(void *arg0)
    {
    UART_Params uartParams;
    ADCBuf_Handle adcBuf;
    ADCBuf_Params adcBufParams;
    ADCBuf_Conversion continuousConversion[4];

    /* Call driver init functions */
    ADCBuf_init();
    UART_init();

    /* Create a UART with data processing off. */
    UART_Params_init(&uartParams);
    uartParams.writeDataMode = UART_DATA_BINARY;
    uartParams.writeMode = UART_MODE_CALLBACK;
    uartParams.writeCallback = uartCallback;
    uartParams.baudRate = 115200;
    uart = UART_open(Board_UART0, &uartParams);

    /* Set up an ADCBuf peripheral in ADCBuf_RECURRENCE_MODE_CONTINUOUS */
    ADCBuf_Params_init(&adcBufParams);
    adcBufParams.callbackFxn = adcBufCallback;
    adcBufParams.recurrenceMode = ADCBuf_RECURRENCE_MODE_CONTINUOUS;
    adcBufParams.returnMode = ADCBuf_RETURN_MODE_CALLBACK;
    adcBufParams.samplingFrequency = 200;
    adcBuf = ADCBuf_open(Board_ADCBUF0, &adcBufParams);

    /* Configure the conversion struct */
    continuousConversion[0].arg = NULL;
    continuousConversion[0].adcChannel = Board_ADCBUF0CHANNEL6;
    continuousConversion[0].sampleBuffer = sampleBufferOne;
    continuousConversion[0].sampleBufferTwo = sampleBufferTwo;
    continuousConversion[0].samplesRequestedCount = ADCBUFFERSIZE;

    continuousConversion[1].arg = NULL;
    continuousConversion[1].adcChannel = Board_ADCBUF0CHANNEL8;
    continuousConversion[1].sampleBuffer = sampleBufferThree;
    continuousConversion[1].sampleBufferTwo = sampleBufferFour;
    continuousConversion[1].samplesRequestedCount = ADCBUFFERSIZE;

    continuousConversion[2].arg = NULL;
    continuousConversion[2].adcChannel = Board_ADCBUF0CHANNEL13;
    continuousConversion[2].sampleBuffer = sampleBufferFive;
    continuousConversion[2].sampleBufferTwo = sampleBufferSix;
    continuousConversion[2].samplesRequestedCount = ADCBUFFERSIZE;

    continuousConversion[3].arg = NULL;
    continuousConversion[3].adcChannel = Board_ADCBUF0CHANNEL14;
    continuousConversion[3].sampleBuffer = sampleBufferSeven;
    continuousConversion[3].sampleBufferTwo = sampleBufferEight;
    continuousConversion[3].samplesRequestedCount = ADCBUFFERSIZE;


    if (adcBuf == NULL){
    /* ADCBuf failed to open. */
    while(1);
    }

    /* Start converting. */
    if (ADCBuf_convert(adcBuf, continuousConversion, 4) !=
    ADCBuf_STATUS_SUCCESS) {
    /* Did not start conversion process correctly. */
    while(1);
    }

    /*
    * Go to sleep in the foreground thread forever. The ADC hardware will
    * perform conversions and invoke the callback function when a buffer is
    * full.
    */
    while(1) {
    sleep(1000);
    }
    }

    However, only P4.7 gives 3.3V reading as I test it with a 3.3V input. P4.5, P4.0 and P6.1 are either not reading anything or give wrong readings.

    Please advise, and thanks!

  • I have MSP-EXP432P401R launchPad, so we can use it instead of CC2640.

    And I have tried to use MSP-EXP432P401R launchPad too.

    In "Board.h" file, I added those pin definations below, and I'm using P4.7, P4.5, P4.0 and P6.1 for 4x analog inputs:

    #define Board_ADCBUF0CHANNEL6 MSP_EXP432P401R_ADCBUF0CHANNEL6 // P4.7
    #define Board_ADCBUF0CHANNEL8 MSP_EXP432P401R_ADCBUF0CHANNEL8 // P4.5
    #define Board_ADCBUF0CHANNEL13 MSP_EXP432P401R_ADCBUF0CHANNEL13 // P4.0
    #define Board_ADCBUF0CHANNEL14 MSP_EXP432P401R_ADCBUF0CHANNEL14 // P6.1

    In "MSP_EXP432P401R.h" file, I added:

    typedef enum MSP_EXP432P401R_ADCBuf0ChannelName {
    MSP_EXP432P401R_ADCBUF0CHANNEL0 = 0,
    MSP_EXP432P401R_ADCBUF0CHANNEL1,
    MSP_EXP432P401R_ADCBUF0CHANNEL6,
    MSP_EXP432P401R_ADCBUF0CHANNEL8,
    MSP_EXP432P401R_ADCBUF0CHANNEL13,
    MSP_EXP432P401R_ADCBUF0CHANNEL14,

    In "MSP_EXP432P401R.c" file, I added:

    ADCBufMSP432_Channels adcBuf0MSP432Channels[MSP_EXP432P401R_ADCBUF0CHANNELCOUNT] = {
    {
    .adcPin = ADCBufMSP432_P5_5_A0,
    .refSource = ADCBufMSP432_VREFPOS_AVCC_VREFNEG_VSS,
    .refVoltage = 3300000,
    .adcInputMode = ADCBufMSP432_SINGLE_ENDED,
    .adcDifferentialPin = ADCBufMSP432_PIN_NONE,
    .adcInternalSource = ADCBufMSP432_INTERNAL_SOURCE_MODE_OFF
    },
    {
    .adcPin = ADCBufMSP432_P5_4_A1,
    .refSource = ADCBufMSP432_VREFPOS_INTBUF_VREFNEG_VSS,
    .refVoltage = 2500000,
    .adcInputMode = ADCBufMSP432_SINGLE_ENDED,
    .adcDifferentialPin = ADCBufMSP432_PIN_NONE,
    .adcInternalSource = ADCBufMSP432_INTERNAL_SOURCE_MODE_OFF
    },
    {
    .adcPin = ADCBufMSP432_P4_7_A6,
    .refSource = ADCBufMSP432_VREFPOS_INTBUF_VREFNEG_VSS,
    .refVoltage = 3300000,
    .adcInputMode = ADCBufMSP432_SINGLE_ENDED,
    .adcDifferentialPin = ADCBufMSP432_PIN_NONE,
    .adcInternalSource = ADCBufMSP432_INTERNAL_SOURCE_MODE_OFF
    },
    {
    .adcPin = ADCBufMSP432_P4_5_A8,
    .refSource = ADCBufMSP432_VREFPOS_INTBUF_VREFNEG_VSS,
    .refVoltage = 3300000,
    .adcInputMode = ADCBufMSP432_SINGLE_ENDED,
    .adcDifferentialPin = ADCBufMSP432_PIN_NONE,
    .adcInternalSource = ADCBufMSP432_INTERNAL_SOURCE_MODE_OFF
    },
    {
    .adcPin = ADCBufMSP432_P4_0_A13,
    .refSource = ADCBufMSP432_VREFPOS_INTBUF_VREFNEG_VSS,
    .refVoltage = 3300000,
    .adcInputMode = ADCBufMSP432_SINGLE_ENDED,
    .adcDifferentialPin = ADCBufMSP432_PIN_NONE,
    .adcInternalSource = ADCBufMSP432_INTERNAL_SOURCE_MODE_OFF
    },
    {
    .adcPin = ADCBufMSP432_P6_1_A14,
    .refSource = ADCBufMSP432_VREFPOS_INTBUF_VREFNEG_VSS,
    .refVoltage = 3300000,
    .adcInputMode = ADCBufMSP432_SINGLE_ENDED,
    .adcDifferentialPin = ADCBufMSP432_PIN_NONE,
    .adcInternalSource = ADCBufMSP432_INTERNAL_SOURCE_MODE_OFF
    },
    };

    In "adcBufContinuousSampling.c" file, I added:

    uint16_t sampleBufferOne[ADCBUFFERSIZE];
    uint16_t sampleBufferTwo[ADCBUFFERSIZE];
    uint16_t sampleBufferThree[ADCBUFFERSIZE];
    uint16_t sampleBufferFour[ADCBUFFERSIZE];
    uint16_t sampleBufferFive[ADCBUFFERSIZE];
    uint16_t sampleBufferSix[ADCBUFFERSIZE];
    uint16_t sampleBufferSeven[ADCBUFFERSIZE];
    uint16_t sampleBufferEight[ADCBUFFERSIZE];



    * ======== mainThread (also modified here) ========
    */
    void *mainThread(void *arg0)
    {
    UART_Params uartParams;
    ADCBuf_Handle adcBuf;
    ADCBuf_Params adcBufParams;
    ADCBuf_Conversion continuousConversion[4];

    /* Call driver init functions */
    ADCBuf_init();
    UART_init();

    /* Create a UART with data processing off. */
    UART_Params_init(&uartParams);
    uartParams.writeDataMode = UART_DATA_BINARY;
    uartParams.writeMode = UART_MODE_CALLBACK;
    uartParams.writeCallback = uartCallback;
    uartParams.baudRate = 115200;
    uart = UART_open(Board_UART0, &uartParams);

    /* Set up an ADCBuf peripheral in ADCBuf_RECURRENCE_MODE_CONTINUOUS */
    ADCBuf_Params_init(&adcBufParams);
    adcBufParams.callbackFxn = adcBufCallback;
    adcBufParams.recurrenceMode = ADCBuf_RECURRENCE_MODE_CONTINUOUS;
    adcBufParams.returnMode = ADCBuf_RETURN_MODE_CALLBACK;
    adcBufParams.samplingFrequency = 200;
    adcBuf = ADCBuf_open(Board_ADCBUF0, &adcBufParams);

    /* Configure the conversion struct */
    continuousConversion[0].arg = NULL;
    continuousConversion[0].adcChannel = Board_ADCBUF0CHANNEL6;
    continuousConversion[0].sampleBuffer = sampleBufferOne;
    continuousConversion[0].sampleBufferTwo = sampleBufferTwo;
    continuousConversion[0].samplesRequestedCount = ADCBUFFERSIZE;

    continuousConversion[1].arg = NULL;
    continuousConversion[1].adcChannel = Board_ADCBUF0CHANNEL8;
    continuousConversion[1].sampleBuffer = sampleBufferThree;
    continuousConversion[1].sampleBufferTwo = sampleBufferFour;
    continuousConversion[1].samplesRequestedCount = ADCBUFFERSIZE;

    continuousConversion[2].arg = NULL;
    continuousConversion[2].adcChannel = Board_ADCBUF0CHANNEL13;
    continuousConversion[2].sampleBuffer = sampleBufferFive;
    continuousConversion[2].sampleBufferTwo = sampleBufferSix;
    continuousConversion[2].samplesRequestedCount = ADCBUFFERSIZE;

    continuousConversion[3].arg = NULL;
    continuousConversion[3].adcChannel = Board_ADCBUF0CHANNEL14;
    continuousConversion[3].sampleBuffer = sampleBufferSeven;
    continuousConversion[3].sampleBufferTwo = sampleBufferEight;
    continuousConversion[3].samplesRequestedCount = ADCBUFFERSIZE;


    if (adcBuf == NULL){
    /* ADCBuf failed to open. */
    while(1);
    }

    /* Start converting. */
    if (ADCBuf_convert(adcBuf, continuousConversion, 4) !=
    ADCBuf_STATUS_SUCCESS) {
    /* Did not start conversion process correctly. */
    while(1);
    }

    /*
    * Go to sleep in the foreground thread forever. The ADC hardware will
    * perform conversions and invoke the callback function when a buffer is
    * full.
    */
    while(1) {
    sleep(1000);
    }
    }

    However, only P4.7 gives 3.3V reading as I test it with a 3.3V input. P4.5, P4.0 and P6.1 are either not reading anything or give wrong readings.

    Please advise, and thanks!
  • Please find the attached project for the MSP432P401R.  

    adcMulti_test.zip

    A couple of things to note:

    (1) The frequency of the system is reduced.  I tried a 100 samples per second to make the terminal more visible but that required moving to power performance level 1.

    (2) useDMA = 0, I do not know what will happen if the DMA is enabled with multiple channels.  If I am going to measure a sequence of channels continuously with the DMA, then the scatter-gather DMA implementation is needed but not supported in the current drivers.  Driverlib examples are available.

    Regards,
    Chris

  • Hi Chris, 

    Thanks for your help so far!

    It finally works with multiple channels, there are some cross talks among channels. (as I input 3.3V to one of channel, other channel would have some values too)

    I will assign channels differently to see if it helps.

    I realize that this example didn't do the conversion from Raw values to MicroVoltage, is there a way that we can add this feature easily?

    Thanks!

  • I am a little unclear on when is the best time to do that. My first thought would be to do that conversion after all of the buffers are filled. Depending upon the rate at which the channels finish, you may be able to perform the conversions on a a per channel basis. Specifically, if the ADC is triggered manually from a timer if the time between samples is long enough then you could do the microvoltage conversion on channel n before the last sample of the buffer for channel n+1 is completed. If the channels are being triggered automatically, then I think you should wait and do the conversion on all the channels after the posting of the semaphore.

    In either case the conversion should be relatively straight forward. In both the context of the callback and the mainthread you will have the necessary information.

    Let me know if that is not clear.

    Chris
  • Hi Chris, 

    I will probably process conversion in computer, this is mush easier.

    Thanks for your help!

    TH

  • Hi Chris, 

    One last question.

    What is the total samples per second for all four channels? and for each channel?

    The buffer is defined as "#define ADCBUFFERSIZE    (2)", and we have changed "adcBufParams.samplingFrequency" to be 100.

    How should I properly interpret the output below, and if I change "ADCBUFFERSIZE" to be (1), the program seems to only output once and then stop. 

    Primary Buffers 17 finished:

    Channel 0:
    6415,
    6415,

    Channel 1:
    746,
    736,

    Channel 2:
    0,
    0,

    Channel 3:
    0,
    0,

    Alternate Buffers 17 finished:

    Channel 0:
    6402,
    6408,

    Channel 1:
    640,
    695,

    Channel 2:
    0,
    0,

    Channel 3:
    0,
    0,

    Thanks

  • This will depend upon the .adcTriggerSource found in MSP_EXP432P401R. In terms of the sequence the order will be
    Channel 0 Sample 1
    Channel 1 Sample 1
    Channel 2 Sample 1
    Channel 3 Sample 1
    Channel 0 Sample 2
    Channel 1 Sample 2
    Channel 2 Sample 2
    Channel 3 Sample 2

    Now the time between samples will either be '0', when the trigger is ADCBufMSP432_SOFTWARE_AUTOMATIC_TRIGGER or defined by the frequency in the application if ADCBufMSP432_TIMER_TRIGGER. While the frequency is 100Hz this means that the time between each sample is 10ms and that each sample is effectively sampled at 40ms or 25Hz.

    ADCBufMSP432_SOFTWARE_AUTOMATIC_TRIGGER -> the first trigger is from Software and all remaining triggers happen automatically when the previous conversion is finished.

    ADCBufMSP432_TIMER_TRIGGER -> each sample is triggered from the timer

    Regards,
    Chris
  • Got it, and thanks. This is very clear.