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.

LAUNCHXL-CC2640R2: Add sample specific data to ADCbuf

Part Number: LAUNCHXL-CC2640R2

So I'm using a code based off the ADCbuf example to read voltages from various sensors and trying to send the data over UART to a terminal program. Can I create a buffer that will populate with which channel goes with which reading? I've tried reducing the buffer size, which works, but I don't want to have such a small buffer that the MCU is constantly sending a data stream over UART. It doesn't seem power efficient to me.

#include <unistd.h>
#include <stdint.h>
#include <stddef.h>

/* Driver Header files */
#include <ti/drivers/GPIO.h>
#include <ti/drivers/PIN.h>
#include <ti/drivers/UART.h>
#include <ti/drivers/ADCBuf.h>
// #include <ti/drivers/Watchdog.h>

/* Board Header file */
#include "Board.h"
#include <ti/drivers/timer/GPTimerCC26XX.h>
#include <ti/drivers/Power.h>
#include <ti/drivers/power/PowerCC26XX.h>
#include <ti/sysbios/BIOS.h>
#include <ti/sysbios/knl/Task.h>
#include <xdc/runtime/Types.h>

/////////////////////////// pin configuration ///////////////////////
/* Pin driver handles */
static PIN_Handle muxPinHandle;

/* Global memory storage for a PIN_Config table */
static PIN_State muxPinState;

/* Global Variables */
unsigned int muxidx = 0;
unsigned int muxmod = 0;
static int channels = 10;
int status = 3;

static int ADCFREQ = 100;
static int MUXFREQ = 5;

PIN_Config muxPinTable[] = {
    IOID_21 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MAX, //EN
    IOID_22 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MAX, //A3
    IOID_23 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MAX, //A2
    IOID_12 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MAX, //A1
    IOID_15 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MAX, //A0
    PIN_TERMINATE
};

/////////////////////////// mux task configuration ///////////////////////
/* Task data */
//Task_Struct timerTask;
//char timerTaskStack[512];

GPTimerCC26XX_Handle hMUXTimer;
void timerCallback(GPTimerCC26XX_Handle handle, GPTimerCC26XX_IntMask interruptMask) {
    // interrupt callback code goes here. Minimize processing in interrupt.
    GPIO_toggle(Board_GPIO_LED0);
        muxmod = muxidx % channels; //get remainder of muxidx for switch
    switch(muxmod) {
        case 0:
            PIN_setOutputValue(muxPinHandle, IOID_22, 0);
            PIN_setOutputValue(muxPinHandle, IOID_23, 0);
            PIN_setOutputValue(muxPinHandle, IOID_12, 0);
            PIN_setOutputValue(muxPinHandle, IOID_15, 0);
            break;
        case 1:
            PIN_setOutputValue(muxPinHandle, IOID_22, 0);
            PIN_setOutputValue(muxPinHandle, IOID_23, 0);
            PIN_setOutputValue(muxPinHandle, IOID_12, 0);
            PIN_setOutputValue(muxPinHandle, IOID_15, 1);
            break;
        case 2:
            PIN_setOutputValue(muxPinHandle, IOID_22, 0);
            PIN_setOutputValue(muxPinHandle, IOID_23, 0);
            PIN_setOutputValue(muxPinHandle, IOID_12, 1);
            PIN_setOutputValue(muxPinHandle, IOID_15, 0);
            break;
        case 3:
            PIN_setOutputValue(muxPinHandle, IOID_22, 0);
            PIN_setOutputValue(muxPinHandle, IOID_23, 0);
            PIN_setOutputValue(muxPinHandle, IOID_12, 1);
            PIN_setOutputValue(muxPinHandle, IOID_15, 1);
            break;
        case 4:
            PIN_setOutputValue(muxPinHandle, IOID_22, 0);
            PIN_setOutputValue(muxPinHandle, IOID_23, 1);
            PIN_setOutputValue(muxPinHandle, IOID_12, 0);
            PIN_setOutputValue(muxPinHandle, IOID_15, 0);
            break;
        case 5:
            PIN_setOutputValue(muxPinHandle, IOID_22, 0);
            PIN_setOutputValue(muxPinHandle, IOID_23, 1);
            PIN_setOutputValue(muxPinHandle, IOID_12, 0);
            PIN_setOutputValue(muxPinHandle, IOID_15, 1);
            break;
        case 6:
            PIN_setOutputValue(muxPinHandle, IOID_22, 0);
            PIN_setOutputValue(muxPinHandle, IOID_23, 1);
            PIN_setOutputValue(muxPinHandle, IOID_12, 1);
            PIN_setOutputValue(muxPinHandle, IOID_15, 0);
            break;
        case 7:
            PIN_setOutputValue(muxPinHandle, IOID_22, 0);
            PIN_setOutputValue(muxPinHandle, IOID_23, 1);
            PIN_setOutputValue(muxPinHandle, IOID_12, 1);
            PIN_setOutputValue(muxPinHandle, IOID_15, 1);
            break;
        case 8:
            PIN_setOutputValue(muxPinHandle, IOID_22, 1);
            PIN_setOutputValue(muxPinHandle, IOID_23, 0);
            PIN_setOutputValue(muxPinHandle, IOID_12, 0);
            PIN_setOutputValue(muxPinHandle, IOID_15, 0);
            break;
        case 9:
            PIN_setOutputValue(muxPinHandle, IOID_22, 1);
            PIN_setOutputValue(muxPinHandle, IOID_23, 0);
            PIN_setOutputValue(muxPinHandle, IOID_12, 0);
            PIN_setOutputValue(muxPinHandle, IOID_15, 1);
            break;
        case 10:
            PIN_setOutputValue(muxPinHandle, IOID_22, 1);
            PIN_setOutputValue(muxPinHandle, IOID_23, 0);
            PIN_setOutputValue(muxPinHandle, IOID_12, 1);
            PIN_setOutputValue(muxPinHandle, IOID_15, 0);
            break;
        case 11:
            PIN_setOutputValue(muxPinHandle, IOID_22, 1);
            PIN_setOutputValue(muxPinHandle, IOID_23, 0);
            PIN_setOutputValue(muxPinHandle, IOID_12, 1);
            PIN_setOutputValue(muxPinHandle, IOID_15, 1);
            break;
        case 12:
            PIN_setOutputValue(muxPinHandle, IOID_22, 1);
            PIN_setOutputValue(muxPinHandle, IOID_23, 1);
            PIN_setOutputValue(muxPinHandle, IOID_12, 0);
            PIN_setOutputValue(muxPinHandle, IOID_15, 0);
            break;
        case 13:
            PIN_setOutputValue(muxPinHandle, IOID_22, 1);
            PIN_setOutputValue(muxPinHandle, IOID_23, 1);
            PIN_setOutputValue(muxPinHandle, IOID_12, 0);
            PIN_setOutputValue(muxPinHandle, IOID_15, 1);
            break;
        case 14:
            PIN_setOutputValue(muxPinHandle, IOID_22, 1);
            PIN_setOutputValue(muxPinHandle, IOID_23, 1);
            PIN_setOutputValue(muxPinHandle, IOID_12, 1);
            PIN_setOutputValue(muxPinHandle, IOID_15, 0);
            break;
        case 15:
            PIN_setOutputValue(muxPinHandle, IOID_22, 1);
            PIN_setOutputValue(muxPinHandle, IOID_23, 1);
            PIN_setOutputValue(muxPinHandle, IOID_12, 1);
            PIN_setOutputValue(muxPinHandle, IOID_15, 1);
            break;
    }
    if(muxidx == channels){
    muxidx = 0; //reset counter back to zero, if it equals the number of channels
    }
    muxidx += 1; // increment counter
    
    
}



/////////////////////////// ADCbuf/UART configuration ///////////////////////
#define ADCBUFFERSIZE    (5)
#define UARTBUFFERSIZE   ((20 * ADCBUFFERSIZE) + 24)

uint16_t sampleBufferOne[ADCBUFFERSIZE];
uint16_t sampleBufferTwo[ADCBUFFERSIZE];
uint32_t microVoltBuffer[ADCBUFFERSIZE];
uint32_t buffersCompletedCounter = 0;
char uartTxBuffer[UARTBUFFERSIZE];

/* Driver handle shared between the task and the callback function */
UART_Handle uart;

/*
 * This function is called whenever an ADC buffer is full.
 * The content of the buffer is then converted into human-readable format and
 * sent to the PC via UART.
 */
void adcBufCallback(ADCBuf_Handle handle, ADCBuf_Conversion *conversion,
    void *completedADCBuffer, uint32_t completedChannel)
{
    uint_fast16_t i;
    uint_fast16_t uartTxBufferOffset = 0;

    /* Adjust raw ADC values and convert them to microvolts */
    ADCBuf_adjustRawValues(handle, completedADCBuffer, ADCBUFFERSIZE,
        completedChannel);
    ADCBuf_convertAdjustedToMicroVolts(handle, completedChannel,
        completedADCBuffer, microVoltBuffer, ADCBUFFERSIZE);

    /* Start with a header message. */
    uartTxBufferOffset = snprintf(uartTxBuffer,
        UARTBUFFERSIZE - uartTxBufferOffset, "\r\nBuffer %u finished.",
        (unsigned int)buffersCompletedCounter++);
        
    /* Write channel number to the UART buffer if there is room. */
    if (uartTxBufferOffset < UARTBUFFERSIZE) {
        uartTxBufferOffset += snprintf(uartTxBuffer + uartTxBufferOffset,
            UARTBUFFERSIZE - uartTxBufferOffset, "\r\nChannel: ");

        for (i = 0; i < ADCBUFFERSIZE && uartTxBufferOffset < UARTBUFFERSIZE; i++) {
            uartTxBufferOffset += snprintf(uartTxBuffer + uartTxBufferOffset,
                UARTBUFFERSIZE - uartTxBufferOffset, "%u,",
                (unsigned int)muxmod);
        }
    }

//    /* Write raw adjusted values to the UART buffer if there is room. */
//   uartTxBufferOffset += snprintf(uartTxBuffer + uartTxBufferOffset,
//        UARTBUFFERSIZE - uartTxBufferOffset, "\r\nRaw Buffer: ");
//
//    for (i = 0; i < ADCBUFFERSIZE && uartTxBufferOffset < UARTBUFFERSIZE; i++) {
//        uartTxBufferOffset += snprintf(uartTxBuffer + uartTxBufferOffset,
//            UARTBUFFERSIZE - uartTxBufferOffset, "%u,",
//        *(((uint16_t *)completedADCBuffer) + i));
//    }

    /* Write microvolt values to the UART buffer if there is room. */
    if (uartTxBufferOffset < UARTBUFFERSIZE) {
        uartTxBufferOffset += snprintf(uartTxBuffer + uartTxBufferOffset,
            UARTBUFFERSIZE - uartTxBufferOffset, "\r\nMicrovolts: ");

        for (i = 0; i < ADCBUFFERSIZE && uartTxBufferOffset < UARTBUFFERSIZE; i++) {
            uartTxBufferOffset += snprintf(uartTxBuffer + uartTxBufferOffset,
                UARTBUFFERSIZE - uartTxBufferOffset, "%u,",
                (unsigned int)microVoltBuffer[i]);
        }
    }

    /*
     * Ensure we don't write outside the buffer.
     * Append a newline after the data.
     */
    if (uartTxBufferOffset < UARTBUFFERSIZE) {
        uartTxBuffer[uartTxBufferOffset++] = '\n';
    }
    else {
        uartTxBuffer[UARTBUFFERSIZE-1] = '\n';
    }

    /* Display the data via UART */
    UART_write(uart, uartTxBuffer, uartTxBufferOffset);
}

/*
 * Callback function to use the UART in callback mode. It does nothing.
 */
void uartCallback(UART_Handle handle, void *buf, size_t count) {
   return;
}

/*
 *  ======== mainThread ========
 */
void *mainThread(void *arg0)
{
    /////////////////////////// mux ///////////////////////
    muxPinHandle = PIN_open(&muxPinState, muxPinTable);
    if(!muxPinHandle) {
        /* Error initializing mux output pins */
        while(1);
    }
    PIN_setOutputValue(muxPinHandle, IOID_21, 1);
    
    /////////////////////////// GPIO ///////////////////////
    
     /* Call driver init functions */
    GPIO_init();

    /* Configure the LED pins */
    GPIO_setConfig(Board_GPIO_LED0, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW);

    /* Turn on user LED */
    GPIO_write(Board_GPIO_LED0, Board_GPIO_LED_ON);
    
/////////////////////////// ADCbuf/ UART /////////////////////// 
    UART_Params uartParams;
    ADCBuf_Handle adcBuf;
    ADCBuf_Params adcBufParams;
    ADCBuf_Conversion continuousConversion;

    /* 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 = ADCFREQ;
    adcBuf = ADCBuf_open(Board_ADCBUF0, &adcBufParams);

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

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

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

  GPTimerCC26XX_Params paramsMUX;
  GPTimerCC26XX_Params_init(&paramsMUX);
  paramsMUX.width          = GPT_CONFIG_32BIT;
  paramsMUX.mode           = GPT_MODE_PERIODIC_UP;
  paramsMUX.debugStallMode = GPTimerCC26XX_DEBUG_STALL_OFF;
  hMUXTimer = GPTimerCC26XX_open(CC2640R2_LAUNCHXL_GPTIMER1A, &paramsMUX); //Need timer 0A for ADCbuf
  if(hMUXTimer == NULL) {
    Task_exit();
  }

  Types_FreqHz  freq;
  BIOS_getCpuFreq(&freq); //48MHz
  //GPTimerCC26XX_Value loadVal = freq.lo / 1000; //47999 = 1ms. 1 clock tick = 1/48e6
  //GPTimerCC26XX_Value loadVal = 48000000; //48e6 = 1 sec
  GPTimerCC26XX_Value loadValMUX = 48000000/MUXFREQ; //24e6 = 0.5 sec
  loadValMUX = loadValMUX - 1;
  GPTimerCC26XX_setLoadValue(hMUXTimer, loadValMUX);
  GPTimerCC26XX_registerInterrupt(hMUXTimer, timerCallback, GPT_INT_TIMEOUT);

  GPTimerCC26XX_start(hMUXTimer);

  /* Start TI-RTOS */
 // BIOS_start();

  
  while(1) {
    Task_sleep(BIOS_WAIT_FOREVER);
  }
}

  • Could you be more specific what you want to add to the driver? From the description/ code it's not too easy to undertand.

    Is the mainthread the only thread you are planning to have in your code? The reason I ask is how you have written the adcbuff callback. A callback can be viewed as a interrupt handling routine (bit simplified) and hence the amount of processing in the callback should be limited. UART read/ write takes time and will therefore block for everything else when placed in a callback. 

  • mainthread is the only thread I will be using. I want to add a buffer that tells what muxmod is when a sample is taken. So for 5 samples, I may get: 553, 553, 941, 941, 941. And I want a second buffer to store the muxmod number: 2, 2, 3, 3, 3. That way I can tell which sample can from which sensor.

    The whole reason that I need to do this that out of the 16 mux channels only two or three may have a higher voltage reading at a single time and I need to know which ones are being activated and what their voltage levels are.

  • Not sure if I understand your setup: Do you have an external 16:1 mux that you control with 4 DIOs?

    This is something you should be able to do by making your own version of C:\ti\simplelink_cc2640r2_sdk_3_20_00_21\source\ti\drivers\adcbuf\ADCBufCC26XX.c/h where you give the mux value and the extra buffer as extra parameter to the convert function and store this in the given buffer. I don't believe this will alter the existing driver functionality. We don't have the bandwidth to do custom modifications to the driver for you but the full source code is provided with should make it possible to see how the driver can be changed to do what you want. 

  • Thank you TER. This was the conclusion I came to myself yesterday. I just didn't know where to even begin. But thank you for clarifying things and helping me out!