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.

Help: Unable to trigger ADC using General Purpose Timer 1A time-out event on CC2650 (SmartRF06EB+CC2650EM-7ID).

Other Parts Discussed in Thread: CC2650, SYSBIOS, BLE-STACK

I was trying to trigger ADC with GPT1A on CC2650 (SmartRF06EB+CC2650EM-7ID)  but failed to get any ADC output data. The following is my Main_tirtos.c source code. The whole project is modified from ADC Data Logger demo project removing  "RTC-based execution scheduling" and all those initialization code / Execution code .  After running, the program was hanging on the red line:

while (1) { 

adcDac = AUXADCReadFifo();

...

}

Is there anything wrong? Or anyone could show me the right way to trigger ADC with the general purpose timer-out event (not by the AUX-timer). Appreciate for your help!

//*****************************************************************************
//  SENSOR CONTROLLER STUDIO EXAMPLE: ADC DATA LOGGER
//  Operating system: TI-RTOS
//
//  The Sensor Controller is used to sample and buffer a single ADC channel.
//  The ADC samples are stored in a ring-buffer, and the Sensor Controller
//  maintains a head index indicating where the next sample will be written.
//  The sampling interval is specified in the call to scifStartRtcTicksNow().
//  The application wakes up at a fixed asynchronous interval, and transfers
//  the ADC samples over UART (57600 baud, 8-N-1).
//
//  Use a terminal window to connect to the SmartRF06EB's USB Serial Port.
//
//  The DISABLE_LOW_POWER definition can be set to 1 to allow debugging.
//
//
//  Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/
//
//
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions
//  are met:
//
//    Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
//
//    Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.
//
//    Neither the name of Texas Instruments Incorporated nor the names of
//    its contributors may be used to endorse or promote products derived
//    from this software without specific prior written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
//  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
//  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
//  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
//  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
//  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
//  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
//  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
//  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
//  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
//  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//****************************************************************************/
#include <xdc/std.h>
#include <xdc/runtime/Error.h>
#include <ti/sysbios/BIOS.h>
#include <ti/sysbios/knl/Clock.h>
#include <ti/sysbios/knl/Task.h>
#include <ti/sysbios/knl/Semaphore.h>
#include <ti/sysbios/family/arm/cc26xx/Power.h>
#include <ti/sysbios/family/arm/cc26xx/PowerCC2650.h>
#include <ti/drivers/UART.h>
#include <ti/drivers/uart/UARTCC26XX.h>
#include <Board.h>
#include "scif.h"
#include "string.h"
#include "stdio.h"
#include "aux_adc.h"
#include "prcm.h"
#include "timer.h"
#include "event.h"
#include "aux_wuc.h"


#define BV(n)               (1 << (n))


#define DISABLE_LOW_POWER   0


// Display error message if the SCIF driver has been generated with incorrect operating system setting
#ifndef SCIF_OSAL_TIRTOS_H
    #error "Generated SCIF driver supports incorrect operating system. Please change to 'TI-RTOS' in the Sensor Controller Studio project panel and re-generate the driver."
#endif

// Task data
Task_Struct myTask;
Char myTaskStack[1024];


// UART driver objects
UART_Handle uHandle;
UART_Params uParams;




void scTaskAlertCallback(void) {

} // taskAlertCallback




void scCtrlReadyCallback(void) {

} // ctrlReadyCallback


static void adcInit(void)
{
    //intialisation of ADC

    // Enable clock for ADC digital and analog interface (not currently enabled in driver)
    AUXWUCClockEnable(AUX_WUC_ADI_CLOCK|AUX_WUC_SOC_CLOCK);   // was : AUX_WUC_MODCLKEN0_SOC_M|AUX_WUC_MODCLKEN0_AUX_ADI4_M);

    
    // Connect AUX IO7 (DIO23, but also DP2 on XDS110) as analog input.
    AUXADCSelectInput(ADC_COMPB_IN_AUXIO7);  

    AUXADCEnableAsync(AUXADC_REF_FIXED, AUXADC_TRIGGER_GPT1A);
}


void taskFxn(UArg a0, UArg a1) {

    // Initialize UART parameters
    UART_Params_init(&uParams);
    uParams.baudRate      = 115200;
    uParams.writeDataMode = UART_DATA_BINARY;//UART_DATA_TEXT;
    uParams.dataLength    = UART_LEN_8;
    uParams.stopBits      = UART_STOP_ONE;

    // Open UART
    uHandle = UART_open(Board_UART, &uParams);

    // Initialize the Sensor Controller
    scifOsalInit();
    scifOsalRegisterCtrlReadyCallback(scCtrlReadyCallback);
    scifOsalRegisterTaskAlertCallback(scTaskAlertCallback);
    scifInit(&scifDriverSetup);
    //scifStartRtcTicksNow(0x00010000 / 128);
    //scifTaskData.adcTimerTrig.output.adcStartFlag = 0;
    // Configure and start the ADC Data Logger task. The task does not signalize data exchange, but
    // has buffering capacity for 256 samples = 2 seconds
    scifStartTasksNbl(BV(SCIF_ADC_TIMER_TRIG_TASK_ID));

    // Maintain the sample buffer tail index here. The Sensor Controller increments the head index (also
    // starting at 0) each time a sample is stored in the buffer.
    char pLine[120];

    uint32_t adcDac = 0;

    //Initialization and Configuration GPT1A

    /* To use a GPT module, enable the peripheral domain and the appropriate GPT module in the PRCM by
         * writing to the PRCM:GPTCLKGR, the PRCM:GPTCLKGS, and the PRCM:GPTCLKGDS registers, or
         * by using the following driver library functions:
         * PRCMPeripheralRunEnable(uint32_t, ui32Peripheral)
         * PRCMPeripheralSleepEnable(uint32_t, ui32Peripheral)
         * PRCMPeripheralDeepSLeepEnable(uint32_t, ui32Peripheral)
         */
    PRCMPeripheralRunEnable(PRCM_PERIPH_TIMER1);
    PRCMPeripheralSleepEnable(PRCM_PERIPH_TIMER1);
    PRCMPeripheralDeepSleepEnable(PRCM_PERIPH_TIMER1);
    /* 2. Next, load the setting to the clock controller by writing to the PRCM:CLKLOADCTL register */

    //Ensure the timer is disabled (clear the GPT:CTL TnEN register bit) before making any changes.
    Power_setDependency(PERIPH_GPT1);
    TimerDisable(GPT1_BASE, TIMER_A);

    //Write the GPTM Configuration Register (GPT:CFG) with a value of 0x0000 0000
    HWREG(GPT1_BASE + GPT_O_CFG) = 0;

    //Configure the GPTM Timer n Mode Register (GPT:TnMR) TnMR field:
        //(a) Write a value of 0x1 for one-shot mode.
        //(b) Write a value of 0x2 for periodic mode.
    TimerConfigure(GPT1_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PERIODIC | TIMER_CFG_B_ONE_SHOT);

    //Optionally, configure the GPT:TnMR TnSNAPS, TnWOT, TnMTE, and TnCDIR register bits to select
    //whether to capture the value of the free-running timer at time-out, use an external trigger to start
    //counting, configure an additional trigger or interrupt, and count up or down.


    //Load the start value into the GPTM Timer n Interval Load Register (GPT:TnILR).
    TimerLoadSet(GPT1_BASE, TIMER_A, 3750);

    //If interrupts are required, set the appropriate bits in the GPTM Interrupt Mask Register (GPT:IMR).

    // Enable timer trigger output for ADC
    TimerTriggerControl(GPT1_BASE, TIMER_A, true);

    // Configure the event fabric to select the appropiate timer.
    EventRegister(EVENT_AUX_PROG, EVENT_TIMER1_A);


    /* 3. Configure the IOC module to route the output from the GPT module to the IOs. */

    /* The IOC module must then be configured to output the timer signal on the wanted I/O pin. For this,
         * IOCFGn.PORTID must be written to the correct PORTIDs (see Chapter 11, I/O Control, for more
         * details).
         */

    /* init adc */
    adcInit();
    //AUXADCFlushFifo();

    //Set the GPT:CTL TnEN register bit to enable the timer and start counting.
    Power_setConstraint(Power_SB_DISALLOW);
    TimerEnable(GPT1_BASE, TIMER_A);
    
    sprintf(pLine, "sample: \r\n");
    UART_write(uHandle, pLine, strlen(pLine));
    // Main loop
    while (1) {     
        adcDac = AUXADCReadFifo();
        sprintf(pLine, "ADC %d\r\n", adcDac);
        UART_write(uHandle, pLine, strlen(pLine));
    }
} // taskFxn




int main(void) {
    Task_Params taskParams;

    // Optional: Prevent the system from entering standby to allow debugging
#if DISABLE_LOW_POWER
    Power_setConstraint(Power_SB_DISALLOW);
    Power_setConstraint(Power_IDLE_PD_DISALLOW);
#endif


    // Initialize the PIN driver
    PIN_init(BoardGpioInitTable);

    // Configure the OS task
    Task_Params_init(&taskParams);
    taskParams.stack = myTaskStack;
    taskParams.stackSize = sizeof(myTaskStack);
    taskParams.priority = 3;
    Task_construct(&myTask, taskFxn, &taskParams, NULL);

    // Start TI-RTOS
    BIOS_start();
    return 0;

} // main

  • Hello Liang,

    I've requested one of our SCE experts to take a look.

    Best wishes
  • Liang,

    The GP Timers do not have a ADC trigger but you can route the timer interrupt to AUX and use it as an ADC trigger. These register fields are already removed in the latest version as these where only correct for a different chip using the same timers.

    With EventRegister you need to connect the timer event to AUX using the register EVENT.AUXSEL0.
    Also, where is the constant AUXADC_TRIGGER_GPT1A coming from? There are no such trigger source, the trigger you should use is the MCU event going from the MCU domain to AUX (AUXSEL0). In the ADC start trigger list this is called MCU_EV.

    It also seems you are starting up the Sensor Controller. Why are you using this when you are also doing sampling and ADC readouts with the system CPU?

    The PRCM* calls should also not be used. In TI RTOS, Power_setDependency will do the same.

    Regards,
    Svend
  • Dear Svend,

    Thanks for your reply. I checked my register configurations and the following is the result:

    “With EventRegister you need to connect the timer event to AUX using the register EVENT.AUXSEL0.” ==> in my configurations, EVENT.AUXSEL0 = 0x12,which means "GPT1A interrupt event, controlled by GPT1:TAMR"

    "Also, where is the constant AUXADC_TRIGGER_GPT1A coming from" ==> it comes from TI RTOS.  AUXADC_TRIGGER_GPT1A is defined in tirtos_simplelink_2_14_02_22/products/cc26xxware_2_21_03_15980/driverlib/Aux_adc.h:

    #define AUXADC_TRIGGER_GPT1A                (EVENT_AUXSEL0_EV_GPT1A)

    where EVENT_AUXSEL0_EV_GPT1A is defined in tirtos_simplelink_2_14_02_22/products/cc26xxware_2_21_03_159980/inc/Hw_event.h as:

    #define EVENT_AUXSEL0_EV_GPT1A                                      0x00000012

    "the trigger you should use is the MCU event going from the MCU domain to AUX (AUXSEL0). In the ADC start trigger list this is called MCU_EV." ==> in my configurations, EVENT.AUXSEL0 = 0x12 (GPT1A interrupt event, controlled by GPT1:TAMR) and AUX_ANAIF.ADCCTL.START_SRC = 0x1E (1Eh = Selects MCU_EV as start signal)

    "It also seems you are starting up the Sensor Controller. Why are you using this when you are also doing sampling and ADC readouts with the system CPU?" ==> My project is modified based on the "ADC data logger" example project of the Sensor Controller Studio so it does look like starting up the Sensor Controller. However I removed all the instructions within the Sensor Controller so it works as a dummy processer. In an another word, the Sensor Controller does nothing in this project.  Please just ignore it.

    "The PRCM* calls should also not be used. In TI RTOS, Power_setDependency will do the same"==> OK, I remoed those codes.

    I think i should have already followed your advice. However, the issue still remains. Could you please help to give me more advice about how to use the general purpose timer to trigger ADC?  I can provide my project package to you if you want.

    Thank you!


    Regards.

    Liang

  • Hi Liang,

    I was not aware of the AUX ADC driver defines, sorry about that.

    Looking at the code it seems correct.

    - To ensure the ADC setup works fine, does the code do ADC sampling when using a manual trigger instead?
    - Have you checked the ADC FIFOSTAT register to ensure the ADC FIFO did not underflow/overflow?

    You might need to configure the CCP output of the timer in GPT1:TAMR.TCACT and set up a timer compare value as well in addition to create the output needed to trigger the ADC. If the CCP output stays high I -think- the ADC will continue to trigger all the time.

    The current state of the timer event connected to AUX is found in AUX_EVCTL:EVSTAT1.MCU_EV.

    Regards,

    Svend

  • Dear Svend,

    Thanks for your help. I tried under your guidance and the following is the result:

    "To ensure the ADC setup works fine, does the code do ADC sampling when using a manual trigger instead?" ==> Yes, the manual trigger works fine.

    "Have you checked the ADC FIFOSTAT register to ensure the ADC FIFO did not underflow/overflow?" ==> I added some codes for this and no underflow/overflow occurs.

    "You might need to configure the CCP output of the timer in GPT1:TAMR.TCACT and set up a timer compare value as well in addition to create the output needed to trigger the ADC. If the CCP output stays high I -think- the ADC will continue to trigger all the time." ==> I set  GPT1.TAMATCHR = 2000 && GPT1.TAPR=0 && GPT1.TAPMR=0 && GPT1.TAILR=3750, and tried every option on GPT1.TAMR.TCACT, doesn't work.

    "The current state of the timer event connected to AUX is found in AUX_EVCTL:EVSTAT1.MCU_EV."==> AUX_EVCTL.EVSTAT1.MCU_EV keeps ZERO. It looks like that AUX does not receive MCU_EV. 

    Regards.

    Liang

     

     

  • Hi Liang,

    It seems the interrupt from the timer is the event going to AUX. You need to enable the timeout interrupt in the interrupt mask GPT1:IMR.TATOIM.
    Note that this event will remain high until cleared by SW in GPT1:ICLR.TATOCINT.

    Regards,
    Svend
  • Dear Svend,


    Thanks for your advice. It works! However my program is not very stable. I found that if I set  GPT1.GPT_O_TAILR with a smaller value (3750 for example), after some rounds of successful sampling, the ADC Fifo will suddenly keep itself empty and I can not read ADC value any more. But if I set GPT1.GPT_O_TAILR with a larger value (37500 for example), it will run normally much longer. Strange isn't it?  Is there any restriction on the high sampler rate triggered by GPT?

    The following is my source code and FYI.

    //*****************************************************************************
    //  SENSOR CONTROLLER STUDIO EXAMPLE: ADC DATA LOGGER
    //  Operating system: TI-RTOS
    //
    //  The Sensor Controller is used to sample and buffer a single ADC channel.
    //  The ADC samples are stored in a ring-buffer, and the Sensor Controller
    //  maintains a head index indicating where the next sample will be written.
    //  The sampling interval is specified in the call to scifStartRtcTicksNow().
    //  The application wakes up at a fixed asynchronous interval, and transfers
    //  the ADC samples over UART (57600 baud, 8-N-1).
    //
    //  Use a terminal window to connect to the SmartRF06EB's USB Serial Port.
    //
    //  The DISABLE_LOW_POWER definition can be set to 1 to allow debugging.
    //
    //
    //  Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/
    //
    //
    //  Redistribution and use in source and binary forms, with or without
    //  modification, are permitted provided that the following conditions
    //  are met:
    //
    //    Redistributions of source code must retain the above copyright
    //    notice, this list of conditions and the following disclaimer.
    //
    //    Redistributions in binary form must reproduce the above copyright
    //    notice, this list of conditions and the following disclaimer in the
    //    documentation and/or other materials provided with the distribution.
    //
    //    Neither the name of Texas Instruments Incorporated nor the names of
    //    its contributors may be used to endorse or promote products derived
    //    from this software without specific prior written permission.
    //
    //  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    //  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    //  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    //  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    //  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    //  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    //  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    //  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    //  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    //  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    //  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    //****************************************************************************/
    #include <xdc/std.h>
    #include <xdc/runtime/Error.h>
    #include <ti/sysbios/BIOS.h>
    #include <ti/sysbios/knl/Clock.h>
    #include <ti/sysbios/knl/Task.h>
    #include <ti/sysbios/knl/Semaphore.h>
    #include <ti/sysbios/family/arm/cc26xx/Power.h>
    #include <ti/sysbios/family/arm/cc26xx/PowerCC2650.h>
    #include <ti/drivers/UART.h>
    #include <ti/drivers/uart/UARTCC26XX.h>
    #include <Board.h>
    #include "scif.h"
    #include "string.h"
    #include "stdio.h"
    #include "aux_adc.h"
    #include "prcm.h"
    #include "timer.h"
    #include "event.h"
    #include "aux_wuc.h"


    #define BV(n)               (1 << (n))


    #define DISABLE_LOW_POWER   0

    #define CLK_RELOAD_VALUE (3750)
    //#define CLK_RELOAD_VALUE (37500)


    // Display error message if the SCIF driver has been generated with incorrect operating system setting
    #ifndef SCIF_OSAL_TIRTOS_H
        #error "Generated SCIF driver supports incorrect operating system. Please change to 'TI-RTOS' in the Sensor Controller Studio project panel and re-generate the driver."
    #endif

    // Task data
    Task_Struct myTask;
    Char myTaskStack[1024];


    // UART driver objects
    UART_Handle uHandle;
    UART_Params uParams;

    uint16_t sampleBuf[1024];
    uint16_t sampleCnt = 0;



    void scTaskAlertCallback(void) {

    } // taskAlertCallback




    void scCtrlReadyCallback(void) {

    } // ctrlReadyCallback

    void TimerTamractConfig(uint32_t ui32Base, uint32_t ui32Cfg)
    {
        ASSERT(TimerBaseValid(ui32Base));
        ASSERT((GPT_TAMR_TCACT_DIS_CMP == ui32Cfg) \
              || (GPT_TAMR_TCACT_TOG_ON_TO == ui32Cfg) \
              || (GPT_TAMR_TCACT_CLR_ON_TO == ui32Cfg) \
              || (GPT_TAMR_TCACT_SET_ON_TO == ui32Cfg) \
              || (GPT_TAMR_TCACT_SETTOG_ON_TO == ui32Cfg) \
              || (GPT_TAMR_TCACT_CLRTOG_ON_TO == ui32Cfg) \
              || (GPT_TAMR_TCACT_SETCLR_ON_TO == ui32Cfg) \
              || (GPT_TAMR_TCACT_CLRSET_ON_TO == ui32Cfg))
        HWREG(ui32Base + GPT_O_TAMR) &= 0xFFFF1FFF; //clear old tcact field
        HWREG(ui32Base + GPT_O_TAMR) |= ui32Cfg;
    }

    static void adcInitManual(void)
    {
        //intialisation of ADC
        IOCPortConfigureSet(IOID_23, IOC_PORT_AUX_IO, IOC_IOMODE_NORMAL);
        // Enable clock for ADC digital and analog interface (not currently enabled in driver)
        AUXWUCClockEnable(AUX_WUC_ADI_CLOCK|AUX_WUC_SOC_CLOCK);   // was : AUX_WUC_MODCLKEN0_SOC_M|AUX_WUC_MODCLKEN0_AUX_ADI4_M);

        
        // Connect AUX IO7 (DIO23, but also DP2 on XDS110) as analog input.
        AUXADCSelectInput(ADC_COMPB_IN_AUXIO7);  

        AUXADCEnableAsync(AUXADC_REF_FIXED, AUXADC_TRIGGER_MANUAL);
    }

    static void adcInit(void)
    {
        //intialisation of ADC
        IOCPortConfigureSet(IOID_23, IOC_PORT_AUX_IO, IOC_IOMODE_NORMAL);
        // Enable clock for ADC digital and analog interface (not currently enabled in driver)
        AUXWUCClockEnable(AUX_WUC_ADI_CLOCK|AUX_WUC_SOC_CLOCK);   // was : AUX_WUC_MODCLKEN0_SOC_M|AUX_WUC_MODCLKEN0_AUX_ADI4_M);

        
        // Connect AUX IO7 (DIO23, but also DP2 on XDS110) as analog input.
        AUXADCSelectInput(ADC_COMPB_IN_AUXIO7);  

        //AUXADCEnableAsync(AUXADC_REF_FIXED, AUXADC_TRIGGER_GPT1A);
        
        AUXADCEnableSync(AUXADC_REF_FIXED, AUXADC_SAMPLE_TIME_2P7_US, AUXADC_TRIGGER_GPT1A);
    }

    uint32_t fifostat = 0;
    uint32_t
    AUXADCReadFifo1(void) {
        uint8_t pLine[32];
        uint32_t adcFifoStat;
        
        // Wait until there is at least one sample in the FIFO
        while (HWREG(AUX_ANAIF_BASE + AUX_ANAIF_O_ADCFIFOSTAT) & AUX_ANAIF_ADCFIFOSTAT_EMPTY_M) {
                fifostat = AUXADCGetFifoStatus();
        }

        // Return the first sample from the FIFO
        return HWREG(AUX_ANAIF_BASE + AUX_ANAIF_O_ADCFIFO);
    }

    void taskFxn(UArg a0, UArg a1) {

        // Initialize UART parameters
        UART_Params_init(&uParams);
        uParams.baudRate      = 115200;
        uParams.writeDataMode = UART_DATA_BINARY;//UART_DATA_TEXT;
        uParams.dataLength    = UART_LEN_8;
        uParams.stopBits      = UART_STOP_ONE;

        // Open UART
        uHandle = UART_open(Board_UART, &uParams);

        // Initialize the Sensor Controller
        scifOsalInit();
        scifOsalRegisterCtrlReadyCallback(scCtrlReadyCallback);
        scifOsalRegisterTaskAlertCallback(scTaskAlertCallback);
        scifInit(&scifDriverSetup);
        //scifStartRtcTicksNow(0x00010000 / 128);
        //scifTaskData.adcTimerTrig.output.adcStartFlag = 0;
        // Configure and start the ADC Data Logger task. The task does not signalize data exchange, but
        // has buffering capacity for 256 samples = 2 seconds
        scifStartTasksNbl(BV(SCIF_ADC_TIMER_TRIG_TASK_ID));

        // Maintain the sample buffer tail index here. The Sensor Controller increments the head index (also
        // starting at 0) each time a sample is stored in the buffer.
        char pLine[120];

        uint32_t adcDac = 0;

        //Initialization and Configuration GPT1A

        /* To use a GPT module, enable the peripheral domain and the appropriate GPT module in the PRCM by
             * writing to the PRCM:GPTCLKGR, the PRCM:GPTCLKGS, and the PRCM:GPTCLKGDS registers, or
             * by using the following driver library functions:
             * PRCMPeripheralRunEnable(uint32_t, ui32Peripheral)
             * PRCMPeripheralSleepEnable(uint32_t, ui32Peripheral)
             * PRCMPeripheralDeepSLeepEnable(uint32_t, ui32Peripheral)
             */
        //PRCMPeripheralRunEnable(PRCM_PERIPH_TIMER1);
        //PRCMPeripheralSleepEnable(PRCM_PERIPH_TIMER1);
        //PRCMPeripheralDeepSleepEnable(PRCM_PERIPH_TIMER1);
        /* 2. Next, load the setting to the clock controller by writing to the PRCM:CLKLOADCTL register */

        //Ensure the timer is disabled (clear the GPT:CTL TnEN register bit) before making any changes.
        Power_setDependency(PERIPH_GPT1);
        TimerDisable(GPT1_BASE, TIMER_A);

        //Write the GPTM Configuration Register (GPT:CFG) with a value of 0x0000 0000
        HWREG(GPT1_BASE + GPT_O_CFG) = 0;

        //Configure the GPTM Timer n Mode Register (GPT:TnMR) TnMR field:
            //(a) Write a value of 0x1 for one-shot mode.
            //(b) Write a value of 0x2 for periodic mode.
        TimerConfigure(GPT1_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PERIODIC | TIMER_CFG_B_ONE_SHOT);

        //Optionally, configure the GPT:TnMR TnSNAPS, TnWOT, TnMTE, and TnCDIR register bits to select
        //whether to capture the value of the free-running timer at time-out, use an external trigger to start
        //counting, configure an additional trigger or interrupt, and count up or down.


        //Load the start value into the GPTM Timer n Interval Load Register (GPT:TnILR).
        TimerLoadSet(GPT1_BASE, TIMER_A, CLK_RELOAD_VALUE);
        //TimerMatchSet(GPT1_BASE, TIMER_A, 180000);
        //TimerTamractConfig(GPT1_BASE, GPT_TAMR_TCACT_TOG_ON_TO);
        //TimerTamractConfig(GPT1_BASE, GPT_TAMR_TCACT_CLR_ON_TO);
        //TimerTamractConfig(GPT1_BASE, GPT_TAMR_TCACT_SET_ON_TO);
        //TimerTamractConfig(GPT1_BASE, GPT_TAMR_TCACT_SETTOG_ON_TO);
        //TimerTamractConfig(GPT1_BASE, GPT_TAMR_TCACT_CLRTOG_ON_TO);
        //TimerTamractConfig(GPT1_BASE, GPT_TAMR_TCACT_SETCLR_ON_TO);
        //TimerTamractConfig(GPT1_BASE, GPT_TAMR_TCACT_CLRSET_ON_TO);


        //If interrupts are required, set the appropriate bits in the GPTM Interrupt Mask Register (GPT:IMR).

        // Enable timer trigger output for ADC
        TimerTriggerControl(GPT1_BASE, TIMER_A, true);

        // Configure the event fabric to select the appropiate timer.
        EventRegister(EVENT_AUX_PROG, EVENT_TIMER1_A);


        /* 3. Configure the IOC module to route the output from the GPT module to the IOs. */

        /* The IOC module must then be configured to output the timer signal on the wanted I/O pin. For this,
             * IOCFGn.PORTID must be written to the correct PORTIDs (see Chapter 11, I/O Control, for more
             * details).
             */

        //Try Manual Trigger
        //adcInitManual();
        //AUXADCGenManualTrigger();
        //adcDac = AUXADCReadFifo();
        //sprintf(pLine, "ADC %d\r\n", adcDac);
        //UART_write(uHandle, pLine, strlen(pLine));
        
        //AUXADCGenManualTrigger();
        //adcDac = AUXADCReadFifo();
        //sprintf(pLine, "ADC %d\r\n", adcDac);
        //UART_write(uHandle, pLine, strlen(pLine));
        /* init adc */

        adcInit();
        //AUXADCFlushFifo();

        uint32_t adcFifoStat;
        adcFifoStat = AUXADCGetFifoStatus();
            
        
        sprintf(pLine, "Fifo stat: %d\r\n",adcFifoStat);
        UART_write(uHandle, pLine, strlen(pLine));


        //enable GPT1A timeout-int
        TimerIntEnable(GPT1_BASE, TIMER_TIMA_TIMEOUT|TIMER_TIMA_MATCH);
        TimerIntClear(GPT1_BASE, TIMER_TIMA_TIMEOUT|TIMER_TIMA_MATCH);

        //GPT1A stall
        HWREG(GPT1_BASE + GPT_O_CTL) |= 0x2;
        //Set the GPT:CTL TnEN register bit to enable the timer and start counting.
        Power_setConstraint(Power_SB_DISALLOW);
        TimerEnable(GPT1_BASE, TIMER_A);
        
        sprintf(pLine, "sample: \r\n");
        UART_write(uHandle, pLine, strlen(pLine));
        
        // Main loop
        while (1) {
            adcDac = AUXADCReadFifo1();
            TimerIntClear(GPT1_BASE, 0x2F3F);
            sampleBuf[sampleCnt++] = adcDac;
            sampleCnt &= 1023;
            if (512 == sampleCnt) {
                sprintf(pLine, "1");
                UART_write(uHandle, pLine, strlen(pLine));            
            }        
        }
    } // taskFxn




    int main(void) {
        Task_Params taskParams;

        // Optional: Prevent the system from entering standby to allow debugging
    #if DISABLE_LOW_POWER
        Power_setConstraint(Power_SB_DISALLOW);
        Power_setConstraint(Power_IDLE_PD_DISALLOW);
    #endif


        // Initialize the PIN driver
        PIN_init(BoardGpioInitTable);

        // Configure the OS task
        Task_Params_init(&taskParams);
        taskParams.stack = myTaskStack;
        taskParams.stackSize = sizeof(myTaskStack);
        taskParams.priority = 3;
        Task_construct(&myTask, taskFxn, &taskParams, NULL);

        // Start TI-RTOS
        BIOS_start();
        return 0;

    } // main

    Thanks.

    Liang

  • Dear Svend,

    Sorry, the following is my source code.

    //*****************************************************************************
    // SENSOR CONTROLLER STUDIO EXAMPLE: ADC DATA LOGGER
    // Operating system: TI-RTOS
    //
    // The Sensor Controller is used to sample and buffer a single ADC channel.
    // The ADC samples are stored in a ring-buffer, and the Sensor Controller
    // maintains a head index indicating where the next sample will be written.
    // The sampling interval is specified in the call to scifStartRtcTicksNow().
    // The application wakes up at a fixed asynchronous interval, and transfers
    // the ADC samples over UART (57600 baud, 8-N-1).
    //
    // Use a terminal window to connect to the SmartRF06EB's USB Serial Port.
    //
    // The DISABLE_LOW_POWER definition can be set to 1 to allow debugging.
    //
    //
    // Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/
    //
    //
    // Redistribution and use in source and binary forms, with or without
    // modification, are permitted provided that the following conditions
    // are met:
    //
    // Redistributions of source code must retain the above copyright
    // notice, this list of conditions and the following disclaimer.
    //
    // Redistributions in binary form must reproduce the above copyright
    // notice, this list of conditions and the following disclaimer in the
    // documentation and/or other materials provided with the distribution.
    //
    // Neither the name of Texas Instruments Incorporated nor the names of
    // its contributors may be used to endorse or promote products derived
    // from this software without specific prior written permission.
    //
    // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    //****************************************************************************/
    #include <xdc/std.h>
    #include <xdc/runtime/Error.h>
    #include <ti/sysbios/BIOS.h>
    #include <ti/sysbios/knl/Clock.h>
    #include <ti/sysbios/knl/Task.h>
    #include <ti/sysbios/knl/Semaphore.h>
    #include <ti/sysbios/family/arm/cc26xx/Power.h>
    #include <ti/sysbios/family/arm/cc26xx/PowerCC2650.h>
    #include <ti/drivers/UART.h>
    #include <ti/drivers/uart/UARTCC26XX.h>
    #include <Board.h>
    #include "scif.h"
    #include "string.h"
    #include "stdio.h"
    #include "aux_adc.h"
    #include "prcm.h"
    #include "timer.h"
    #include "event.h"
    #include "aux_wuc.h"


    #define BV(n) (1 << (n))


    #define DISABLE_LOW_POWER 0

    #define CLK_RELOAD_VALUE (3750)
    //#define CLK_RELOAD_VALUE (37500)


    // Display error message if the SCIF driver has been generated with incorrect operating system setting
    #ifndef SCIF_OSAL_TIRTOS_H
    #error "Generated SCIF driver supports incorrect operating system. Please change to 'TI-RTOS' in the Sensor Controller Studio project panel and re-generate the driver."
    #endif

    // Task data
    Task_Struct myTask;
    Char myTaskStack[1024];


    // UART driver objects
    UART_Handle uHandle;
    UART_Params uParams;

    uint16_t sampleBuf[1024];
    uint16_t sampleCnt = 0;



    void scTaskAlertCallback(void) {

    } // taskAlertCallback




    void scCtrlReadyCallback(void) {

    } // ctrlReadyCallback

    void TimerTamractConfig(uint32_t ui32Base, uint32_t ui32Cfg)
    {
    ASSERT(TimerBaseValid(ui32Base));
    ASSERT((GPT_TAMR_TCACT_DIS_CMP == ui32Cfg) \
    || (GPT_TAMR_TCACT_TOG_ON_TO == ui32Cfg) \
    || (GPT_TAMR_TCACT_CLR_ON_TO == ui32Cfg) \
    || (GPT_TAMR_TCACT_SET_ON_TO == ui32Cfg) \
    || (GPT_TAMR_TCACT_SETTOG_ON_TO == ui32Cfg) \
    || (GPT_TAMR_TCACT_CLRTOG_ON_TO == ui32Cfg) \
    || (GPT_TAMR_TCACT_SETCLR_ON_TO == ui32Cfg) \
    || (GPT_TAMR_TCACT_CLRSET_ON_TO == ui32Cfg))
    HWREG(ui32Base + GPT_O_TAMR) &= 0xFFFF1FFF; //clear old tcact field
    HWREG(ui32Base + GPT_O_TAMR) |= ui32Cfg;
    }

    static void adcInitManual(void)
    {
    //intialisation of ADC
    IOCPortConfigureSet(IOID_23, IOC_PORT_AUX_IO, IOC_IOMODE_NORMAL);
    // Enable clock for ADC digital and analog interface (not currently enabled in driver)
    AUXWUCClockEnable(AUX_WUC_ADI_CLOCK|AUX_WUC_SOC_CLOCK); // was : AUX_WUC_MODCLKEN0_SOC_M|AUX_WUC_MODCLKEN0_AUX_ADI4_M);


    // Connect AUX IO7 (DIO23, but also DP2 on XDS110) as analog input.
    AUXADCSelectInput(ADC_COMPB_IN_AUXIO7);

    AUXADCEnableAsync(AUXADC_REF_FIXED, AUXADC_TRIGGER_MANUAL);
    }

    static void adcInit(void)
    {
    //intialisation of ADC
    IOCPortConfigureSet(IOID_23, IOC_PORT_AUX_IO, IOC_IOMODE_NORMAL);
    // Enable clock for ADC digital and analog interface (not currently enabled in driver)
    AUXWUCClockEnable(AUX_WUC_ADI_CLOCK|AUX_WUC_SOC_CLOCK); // was : AUX_WUC_MODCLKEN0_SOC_M|AUX_WUC_MODCLKEN0_AUX_ADI4_M);


    // Connect AUX IO7 (DIO23, but also DP2 on XDS110) as analog input.
    AUXADCSelectInput(ADC_COMPB_IN_AUXIO7);

    //AUXADCEnableAsync(AUXADC_REF_FIXED, AUXADC_TRIGGER_GPT1A);

    AUXADCEnableSync(AUXADC_REF_FIXED, AUXADC_SAMPLE_TIME_2P7_US, AUXADC_TRIGGER_GPT1A);
    }

    uint32_t fifostat = 0;
    uint32_t
    AUXADCReadFifo1(void) {
    uint8_t pLine[32];
    uint32_t adcFifoStat;

    // Wait until there is at least one sample in the FIFO
    while (HWREG(AUX_ANAIF_BASE + AUX_ANAIF_O_ADCFIFOSTAT) & AUX_ANAIF_ADCFIFOSTAT_EMPTY_M) {
    fifostat = AUXADCGetFifoStatus();
    }

    // Return the first sample from the FIFO
    return HWREG(AUX_ANAIF_BASE + AUX_ANAIF_O_ADCFIFO);
    }

    void taskFxn(UArg a0, UArg a1) {

    // Initialize UART parameters
    UART_Params_init(&uParams);
    uParams.baudRate = 115200;
    uParams.writeDataMode = UART_DATA_BINARY;//UART_DATA_TEXT;
    uParams.dataLength = UART_LEN_8;
    uParams.stopBits = UART_STOP_ONE;

    // Open UART
    uHandle = UART_open(Board_UART, &uParams);

    // Initialize the Sensor Controller
    scifOsalInit();
    scifOsalRegisterCtrlReadyCallback(scCtrlReadyCallback);
    scifOsalRegisterTaskAlertCallback(scTaskAlertCallback);
    scifInit(&scifDriverSetup);
    //scifStartRtcTicksNow(0x00010000 / 128);
    //scifTaskData.adcTimerTrig.output.adcStartFlag = 0;
    // Configure and start the ADC Data Logger task. The task does not signalize data exchange, but
    // has buffering capacity for 256 samples = 2 seconds
    scifStartTasksNbl(BV(SCIF_ADC_TIMER_TRIG_TASK_ID));

    // Maintain the sample buffer tail index here. The Sensor Controller increments the head index (also
    // starting at 0) each time a sample is stored in the buffer.
    char pLine[120];

    uint32_t adcDac = 0;

    //Initialization and Configuration GPT1A

    /* To use a GPT module, enable the peripheral domain and the appropriate GPT module in the PRCM by
    * writing to the PRCM:GPTCLKGR, the PRCM:GPTCLKGS, and the PRCM:GPTCLKGDS registers, or
    * by using the following driver library functions:
    * PRCMPeripheralRunEnable(uint32_t, ui32Peripheral)
    * PRCMPeripheralSleepEnable(uint32_t, ui32Peripheral)
    * PRCMPeripheralDeepSLeepEnable(uint32_t, ui32Peripheral)
    */
    //PRCMPeripheralRunEnable(PRCM_PERIPH_TIMER1);
    //PRCMPeripheralSleepEnable(PRCM_PERIPH_TIMER1);
    //PRCMPeripheralDeepSleepEnable(PRCM_PERIPH_TIMER1);
    /* 2. Next, load the setting to the clock controller by writing to the PRCM:CLKLOADCTL register */

    //Ensure the timer is disabled (clear the GPT:CTL TnEN register bit) before making any changes.
    Power_setDependency(PERIPH_GPT1);
    TimerDisable(GPT1_BASE, TIMER_A);

    //Write the GPTM Configuration Register (GPT:CFG) with a value of 0x0000 0000
    HWREG(GPT1_BASE + GPT_O_CFG) = 0;

    //Configure the GPTM Timer n Mode Register (GPT:TnMR) TnMR field:
    //(a) Write a value of 0x1 for one-shot mode.
    //(b) Write a value of 0x2 for periodic mode.
    TimerConfigure(GPT1_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PERIODIC | TIMER_CFG_B_ONE_SHOT);

    //Optionally, configure the GPT:TnMR TnSNAPS, TnWOT, TnMTE, and TnCDIR register bits to select
    //whether to capture the value of the free-running timer at time-out, use an external trigger to start
    //counting, configure an additional trigger or interrupt, and count up or down.


    //Load the start value into the GPTM Timer n Interval Load Register (GPT:TnILR).
    TimerLoadSet(GPT1_BASE, TIMER_A, CLK_RELOAD_VALUE);
    //TimerMatchSet(GPT1_BASE, TIMER_A, 180000);
    //TimerTamractConfig(GPT1_BASE, GPT_TAMR_TCACT_TOG_ON_TO);
    //TimerTamractConfig(GPT1_BASE, GPT_TAMR_TCACT_CLR_ON_TO);
    //TimerTamractConfig(GPT1_BASE, GPT_TAMR_TCACT_SET_ON_TO);
    //TimerTamractConfig(GPT1_BASE, GPT_TAMR_TCACT_SETTOG_ON_TO);
    //TimerTamractConfig(GPT1_BASE, GPT_TAMR_TCACT_CLRTOG_ON_TO);
    //TimerTamractConfig(GPT1_BASE, GPT_TAMR_TCACT_SETCLR_ON_TO);
    //TimerTamractConfig(GPT1_BASE, GPT_TAMR_TCACT_CLRSET_ON_TO);


    //If interrupts are required, set the appropriate bits in the GPTM Interrupt Mask Register (GPT:IMR).

    // Enable timer trigger output for ADC
    TimerTriggerControl(GPT1_BASE, TIMER_A, true);

    // Configure the event fabric to select the appropiate timer.
    EventRegister(EVENT_AUX_PROG, EVENT_TIMER1_A);


    /* 3. Configure the IOC module to route the output from the GPT module to the IOs. */

    /* The IOC module must then be configured to output the timer signal on the wanted I/O pin. For this,
    * IOCFGn.PORTID must be written to the correct PORTIDs (see Chapter 11, I/O Control, for more
    * details).
    */

    //Try Manual Trigger
    //adcInitManual();
    //AUXADCGenManualTrigger();
    //adcDac = AUXADCReadFifo();
    //sprintf(pLine, "ADC %d\r\n", adcDac);
    //UART_write(uHandle, pLine, strlen(pLine));

    //AUXADCGenManualTrigger();
    //adcDac = AUXADCReadFifo();
    //sprintf(pLine, "ADC %d\r\n", adcDac);
    //UART_write(uHandle, pLine, strlen(pLine));
    /* init adc */

    adcInit();
    //AUXADCFlushFifo();

    uint32_t adcFifoStat;
    adcFifoStat = AUXADCGetFifoStatus();


    sprintf(pLine, "Fifo stat: %d\r\n",adcFifoStat);
    UART_write(uHandle, pLine, strlen(pLine));


    //enable GPT1A timeout-int
    TimerIntEnable(GPT1_BASE, TIMER_TIMA_TIMEOUT|TIMER_TIMA_MATCH);
    TimerIntClear(GPT1_BASE, TIMER_TIMA_TIMEOUT|TIMER_TIMA_MATCH);

    //GPT1A stall
    HWREG(GPT1_BASE + GPT_O_CTL) |= 0x2;
    //Set the GPT:CTL TnEN register bit to enable the timer and start counting.
    Power_setConstraint(Power_SB_DISALLOW);
    TimerEnable(GPT1_BASE, TIMER_A);

    sprintf(pLine, "sample: \r\n");
    UART_write(uHandle, pLine, strlen(pLine));

    // Main loop
    while (1) {
    adcDac = AUXADCReadFifo1();
    TimerIntClear(GPT1_BASE, 0x2F3F);
    sampleBuf[sampleCnt++] = adcDac;
    sampleCnt &= 1023;
    if (512 == sampleCnt) {
    sprintf(pLine, "1");
    UART_write(uHandle, pLine, strlen(pLine));
    }
    }
    } // taskFxn




    int main(void) {
    Task_Params taskParams;

    // Optional: Prevent the system from entering standby to allow debugging
    #if DISABLE_LOW_POWER
    Power_setConstraint(Power_SB_DISALLOW);
    Power_setConstraint(Power_IDLE_PD_DISALLOW);
    #endif


    // Initialize the PIN driver
    PIN_init(BoardGpioInitTable);

    // Configure the OS task
    Task_Params_init(&taskParams);
    taskParams.stack = myTaskStack;
    taskParams.stackSize = sizeof(myTaskStack);
    taskParams.priority = 3;
    Task_construct(&myTask, taskFxn, &taskParams, NULL);

    // Start TI-RTOS
    BIOS_start();
    return 0;

    } // main


    BR.

    Liang
  • Dear Svend,

    I edit my last post and found it is missing! I don't know whether you can see it or not. So I repost it for case. If it is duplicated, please ignore it. Thanks.

    Dear Svend,


    Thanks for your advice. It works! However my program is not very stable. I found that if I set  GPT1.GPT_O_TAILR with a smaller value (3750 for example), after some rounds of successful sampling, the ADC Fifo will suddenly keep itself empty and I can not read ADC value any more. But if I set GPT1.GPT_O_TAILR with a larger value (37500 for example), it will run normally much longer. Strange isn't it?  Is there any restriction on the high sampler rate triggered by GPT?

    The following is my source code and FYI.

    //*****************************************************************************
    //  SENSOR CONTROLLER STUDIO EXAMPLE: ADC DATA LOGGER
    //  Operating system: TI-RTOS
    //
    //  The Sensor Controller is used to sample and buffer a single ADC channel.
    //  The ADC samples are stored in a ring-buffer, and the Sensor Controller
    //  maintains a head index indicating where the next sample will be written.
    //  The sampling interval is specified in the call to scifStartRtcTicksNow().
    //  The application wakes up at a fixed asynchronous interval, and transfers
    //  the ADC samples over UART (57600 baud, 8-N-1).
    //
    //  Use a terminal window to connect to the SmartRF06EB's USB Serial Port.
    //
    //  The DISABLE_LOW_POWER definition can be set to 1 to allow debugging.
    //
    //
    //  Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/
    //
    //
    //  Redistribution and use in source and binary forms, with or without
    //  modification, are permitted provided that the following conditions
    //  are met:
    //
    //    Redistributions of source code must retain the above copyright
    //    notice, this list of conditions and the following disclaimer.
    //
    //    Redistributions in binary form must reproduce the above copyright
    //    notice, this list of conditions and the following disclaimer in the
    //    documentation and/or other materials provided with the distribution.
    //
    //    Neither the name of Texas Instruments Incorporated nor the names of
    //    its contributors may be used to endorse or promote products derived
    //    from this software without specific prior written permission.
    //
    //  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    //  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    //  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    //  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    //  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    //  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    //  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    //  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    //  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    //  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    //  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    //****************************************************************************/
    #include <xdc/std.h>
    #include <xdc/runtime/Error.h>
    #include <ti/sysbios/BIOS.h>
    #include <ti/sysbios/knl/Clock.h>
    #include <ti/sysbios/knl/Task.h>
    #include <ti/sysbios/knl/Semaphore.h>
    #include <ti/sysbios/family/arm/cc26xx/Power.h>
    #include <ti/sysbios/family/arm/cc26xx/PowerCC2650.h>
    #include <ti/drivers/UART.h>
    #include <ti/drivers/uart/UARTCC26XX.h>
    #include <Board.h>
    #include "scif.h"
    #include "string.h"
    #include "stdio.h"
    #include "aux_adc.h"
    #include "prcm.h"
    #include "timer.h"
    #include "event.h"
    #include "aux_wuc.h"
    
    
    #define BV(n)               (1 << (n))
    
    
    #define DISABLE_LOW_POWER   0
    
    #define CLK_RELOAD_VALUE (3750)
    //#define CLK_RELOAD_VALUE (37500)
    
    
    // Display error message if the SCIF driver has been generated with incorrect operating system setting
    #ifndef SCIF_OSAL_TIRTOS_H
        #error "Generated SCIF driver supports incorrect operating system. Please change to 'TI-RTOS' in the Sensor Controller Studio project panel and re-generate the driver."
    #endif
    
    // Task data
    Task_Struct myTask;
    Char myTaskStack[1024];
    
    
    // UART driver objects
    UART_Handle uHandle;
    UART_Params uParams;
    
    uint16_t sampleBuf[1024];
    uint16_t sampleCnt = 0;
    
    
    
    void scTaskAlertCallback(void) {
    
    } // taskAlertCallback
    
    
    
    
    void scCtrlReadyCallback(void) {
    
    } // ctrlReadyCallback
    
    void TimerTamractConfig(uint32_t ui32Base, uint32_t ui32Cfg)
    {
        ASSERT(TimerBaseValid(ui32Base));
        ASSERT((GPT_TAMR_TCACT_DIS_CMP == ui32Cfg) \
              || (GPT_TAMR_TCACT_TOG_ON_TO == ui32Cfg) \
              || (GPT_TAMR_TCACT_CLR_ON_TO == ui32Cfg) \
              || (GPT_TAMR_TCACT_SET_ON_TO == ui32Cfg) \
              || (GPT_TAMR_TCACT_SETTOG_ON_TO == ui32Cfg) \
              || (GPT_TAMR_TCACT_CLRTOG_ON_TO == ui32Cfg) \
              || (GPT_TAMR_TCACT_SETCLR_ON_TO == ui32Cfg) \
              || (GPT_TAMR_TCACT_CLRSET_ON_TO == ui32Cfg))
        HWREG(ui32Base + GPT_O_TAMR) &= 0xFFFF1FFF; //clear old tcact field
        HWREG(ui32Base + GPT_O_TAMR) |= ui32Cfg;
    }
    
    static void adcInitManual(void)
    {
        //intialisation of ADC
        IOCPortConfigureSet(IOID_23, IOC_PORT_AUX_IO, IOC_IOMODE_NORMAL);
        // Enable clock for ADC digital and analog interface (not currently enabled in driver)
        AUXWUCClockEnable(AUX_WUC_ADI_CLOCK|AUX_WUC_SOC_CLOCK);   // was : AUX_WUC_MODCLKEN0_SOC_M|AUX_WUC_MODCLKEN0_AUX_ADI4_M);
    
        
        // Connect AUX IO7 (DIO23, but also DP2 on XDS110) as analog input.
        AUXADCSelectInput(ADC_COMPB_IN_AUXIO7);  
    
        AUXADCEnableAsync(AUXADC_REF_FIXED, AUXADC_TRIGGER_MANUAL);
    }
    
    static void adcInit(void)
    {
        //intialisation of ADC
        IOCPortConfigureSet(IOID_23, IOC_PORT_AUX_IO, IOC_IOMODE_NORMAL);
        // Enable clock for ADC digital and analog interface (not currently enabled in driver)
        AUXWUCClockEnable(AUX_WUC_ADI_CLOCK|AUX_WUC_SOC_CLOCK);   // was : AUX_WUC_MODCLKEN0_SOC_M|AUX_WUC_MODCLKEN0_AUX_ADI4_M);
    
        
        // Connect AUX IO7 (DIO23, but also DP2 on XDS110) as analog input.
        AUXADCSelectInput(ADC_COMPB_IN_AUXIO7);  
    
        //AUXADCEnableAsync(AUXADC_REF_FIXED, AUXADC_TRIGGER_GPT1A);
        
        AUXADCEnableSync(AUXADC_REF_FIXED, AUXADC_SAMPLE_TIME_2P7_US, AUXADC_TRIGGER_GPT1A);
    }
    
    uint32_t fifostat = 0;
    uint32_t
    AUXADCReadFifo1(void) {
        uint8_t pLine[32];
        uint32_t adcFifoStat;
        
        // Wait until there is at least one sample in the FIFO
        while (HWREG(AUX_ANAIF_BASE + AUX_ANAIF_O_ADCFIFOSTAT) & AUX_ANAIF_ADCFIFOSTAT_EMPTY_M) {
                fifostat = AUXADCGetFifoStatus();
        }
    
        // Return the first sample from the FIFO
        return HWREG(AUX_ANAIF_BASE + AUX_ANAIF_O_ADCFIFO);
    }
    
    void taskFxn(UArg a0, UArg a1) {
    
        // Initialize UART parameters
        UART_Params_init(&uParams);
        uParams.baudRate      = 115200;
        uParams.writeDataMode = UART_DATA_BINARY;//UART_DATA_TEXT;
        uParams.dataLength    = UART_LEN_8;
        uParams.stopBits      = UART_STOP_ONE;
    
        // Open UART
        uHandle = UART_open(Board_UART, &uParams);
    
        // Initialize the Sensor Controller
        scifOsalInit();
        scifOsalRegisterCtrlReadyCallback(scCtrlReadyCallback);
        scifOsalRegisterTaskAlertCallback(scTaskAlertCallback);
        scifInit(&scifDriverSetup);
        //scifStartRtcTicksNow(0x00010000 / 128);
        //scifTaskData.adcTimerTrig.output.adcStartFlag = 0;
        // Configure and start the ADC Data Logger task. The task does not signalize data exchange, but
        // has buffering capacity for 256 samples = 2 seconds
        scifStartTasksNbl(BV(SCIF_ADC_TIMER_TRIG_TASK_ID));
    
        // Maintain the sample buffer tail index here. The Sensor Controller increments the head index (also
        // starting at 0) each time a sample is stored in the buffer.
        char pLine[120];
    
        uint32_t adcDac = 0;
    
        //Initialization and Configuration GPT1A
    
        /* To use a GPT module, enable the peripheral domain and the appropriate GPT module in the PRCM by
             * writing to the PRCM:GPTCLKGR, the PRCM:GPTCLKGS, and the PRCM:GPTCLKGDS registers, or
             * by using the following driver library functions:
             * PRCMPeripheralRunEnable(uint32_t, ui32Peripheral)
             * PRCMPeripheralSleepEnable(uint32_t, ui32Peripheral)
             * PRCMPeripheralDeepSLeepEnable(uint32_t, ui32Peripheral)
             */
        //PRCMPeripheralRunEnable(PRCM_PERIPH_TIMER1);
        //PRCMPeripheralSleepEnable(PRCM_PERIPH_TIMER1);
        //PRCMPeripheralDeepSleepEnable(PRCM_PERIPH_TIMER1);
        /* 2. Next, load the setting to the clock controller by writing to the PRCM:CLKLOADCTL register */
    
        //Ensure the timer is disabled (clear the GPT:CTL TnEN register bit) before making any changes.
        Power_setDependency(PERIPH_GPT1);
        TimerDisable(GPT1_BASE, TIMER_A);
    
        //Write the GPTM Configuration Register (GPT:CFG) with a value of 0x0000 0000
        HWREG(GPT1_BASE + GPT_O_CFG) = 0;
    
        //Configure the GPTM Timer n Mode Register (GPT:TnMR) TnMR field:
            //(a) Write a value of 0x1 for one-shot mode.
            //(b) Write a value of 0x2 for periodic mode.
        TimerConfigure(GPT1_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PERIODIC | TIMER_CFG_B_ONE_SHOT);
    
        //Optionally, configure the GPT:TnMR TnSNAPS, TnWOT, TnMTE, and TnCDIR register bits to select
        //whether to capture the value of the free-running timer at time-out, use an external trigger to start
        //counting, configure an additional trigger or interrupt, and count up or down.
    
    
        //Load the start value into the GPTM Timer n Interval Load Register (GPT:TnILR).
        TimerLoadSet(GPT1_BASE, TIMER_A, CLK_RELOAD_VALUE); 
        //TimerMatchSet(GPT1_BASE, TIMER_A, 180000);
        //TimerTamractConfig(GPT1_BASE, GPT_TAMR_TCACT_TOG_ON_TO);
        //TimerTamractConfig(GPT1_BASE, GPT_TAMR_TCACT_CLR_ON_TO);
        //TimerTamractConfig(GPT1_BASE, GPT_TAMR_TCACT_SET_ON_TO);
        //TimerTamractConfig(GPT1_BASE, GPT_TAMR_TCACT_SETTOG_ON_TO);
        //TimerTamractConfig(GPT1_BASE, GPT_TAMR_TCACT_CLRTOG_ON_TO);
        //TimerTamractConfig(GPT1_BASE, GPT_TAMR_TCACT_SETCLR_ON_TO);
        //TimerTamractConfig(GPT1_BASE, GPT_TAMR_TCACT_CLRSET_ON_TO);
    
    
        //If interrupts are required, set the appropriate bits in the GPTM Interrupt Mask Register (GPT:IMR).
    
        // Enable timer trigger output for ADC
        TimerTriggerControl(GPT1_BASE, TIMER_A, true);
    
        // Configure the event fabric to select the appropiate timer.
        EventRegister(EVENT_AUX_PROG, EVENT_TIMER1_A);
    
    
        /* 3. Configure the IOC module to route the output from the GPT module to the IOs. */
    
        /* The IOC module must then be configured to output the timer signal on the wanted I/O pin. For this,
             * IOCFGn.PORTID must be written to the correct PORTIDs (see Chapter 11, I/O Control, for more
             * details).
             */
    
        //Try Manual Trigger
        //adcInitManual();
        //AUXADCGenManualTrigger();
        //adcDac = AUXADCReadFifo();
        //sprintf(pLine, "ADC %d\r\n", adcDac);
        //UART_write(uHandle, pLine, strlen(pLine));
        
        //AUXADCGenManualTrigger();
        //adcDac = AUXADCReadFifo();
        //sprintf(pLine, "ADC %d\r\n", adcDac);
        //UART_write(uHandle, pLine, strlen(pLine));
        /* init adc */
    
        adcInit();
        //AUXADCFlushFifo();
    
        uint32_t adcFifoStat;
        adcFifoStat = AUXADCGetFifoStatus();
            
        
        sprintf(pLine, "Fifo stat: %d\r\n",adcFifoStat);
        UART_write(uHandle, pLine, strlen(pLine));
    
    
        //enable GPT1A timeout-int
        TimerIntEnable(GPT1_BASE, TIMER_TIMA_TIMEOUT|TIMER_TIMA_MATCH);
        TimerIntClear(GPT1_BASE, TIMER_TIMA_TIMEOUT|TIMER_TIMA_MATCH);
    
        //GPT1A stall
        HWREG(GPT1_BASE + GPT_O_CTL) |= 0x2;
        //Set the GPT:CTL TnEN register bit to enable the timer and start counting.
        Power_setConstraint(Power_SB_DISALLOW);
        TimerEnable(GPT1_BASE, TIMER_A);
        
        sprintf(pLine, "sample: \r\n");
        UART_write(uHandle, pLine, strlen(pLine));
        
        // Main loop
        while (1) {
            adcDac = AUXADCReadFifo1();
            TimerIntClear(GPT1_BASE, 0x2F3F);
            sampleBuf[sampleCnt++] = adcDac;
            sampleCnt &= 1023;
            if (512 == sampleCnt) {
                sprintf(pLine, "1");
                UART_write(uHandle, pLine, strlen(pLine));            
            }        
        }
    } // taskFxn
    
    
    
    
    int main(void) {
        Task_Params taskParams;
    
        // Optional: Prevent the system from entering standby to allow debugging
    #if DISABLE_LOW_POWER
        Power_setConstraint(Power_SB_DISALLOW);
        Power_setConstraint(Power_IDLE_PD_DISALLOW);
    #endif
    
    
        // Initialize the PIN driver
        PIN_init(BoardGpioInitTable);
    
        // Configure the OS task
        Task_Params_init(&taskParams);
        taskParams.stack = myTaskStack;
        taskParams.stackSize = sizeof(myTaskStack);
        taskParams.priority = 3;
        Task_construct(&myTask, taskFxn, &taskParams, NULL);
    
        // Start TI-RTOS
        BIOS_start();
        return 0;
    
    } // main

    Thanks.

    Liang

  • Dear Svend,


    Thanks for your advice. It works! However my program is not very stable. I found that if I set GPT1.GPT_O_TAILR with a smaller value (3750 for example), after some rounds of successful sampling, the ADC Fifo will suddenly keep itself empty and I can not read ADC value any more. But if I set GPT1.GPT_O_TAILR with a larger value (37500 for example), it will run normally much longer. Strange isn't it? Is there any restriction on the high sampler rate triggered by GPT?


    Thanks.
    Liang
  • Liang,

    I would suggest looking at the FIFOSTAT register. You probably have a FIFO under/overflow happening which would cause no more samples to be stored until the FIFO is flushed again.

    For the use case it seems you are working with it would be much simpler and lower-power to perform periodic sampling with the Sensor Controller, store samples to the Sensor Controller RAM and copy over to the Cortex M3 RAM as needed.
  • Dear Svend,

    Firstly I would say "Thank you" for your kindly help.


    I have checked the FIFOSTAT register. I periodly output its value through UART. I found that when this issue occurred, its value keeped as 0x1 which means empty without underflow/upperflow. However after I pause the program and read FIFOSTAT again by stepping the program (Not by watching the register directly, I know that would cause underflow), its value changed to 0x9,which means EMPTY and UNDERFLOW.

    I would like to know about two things.

    1. Which would cause ADC fifo underfolw? My program checks the FIFOSTAT first before reading data from the fifo and I do not watch AUX_ANAIF registers through IAR register watch window.

    2. How to resume ADC from underflow? Flush its FIFO?

    And thanks for your advice that working with the Sensor Controller, yes I know that's a better way and I will try it later.

    BR.

    Liang

  • FIFO underflows happens when reading the FIFO while it is empty. To start sampling again you need to flush the FIFO.
    If you halt while debugging the application you should also set the halt flag in the timer (CTL.TASTALL) so the timer stops while the debugger has halted the CPU.

    Regards,
    Svend
  • Dear Svend,


    I should have already set the halt flag in the timer (CTL.TASTALL) and checked the fifo state before reading data to avoid fifo underflow.  It is very strange to see the ADC sampling suddenly halted. I would try more on it.

    Any way, thanks so much for your help. I really appreciate it.

    BR.

    Liang

  • Hi Svend!

    How should it work? For instance, I need to implement data logging (ADC-200kHz) on CC2650 together with BLE-stack. BUT!!! The size of CRITICAL SECTION inside BLE-stack??? Is there no other ways? Ways in which SW-cleaning of Interrupt Status is not necessary???

    My respect!

    Andrei