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.

LP-MSPM0G3507: Issues with ADC Triggering via Comparator (COMP) in Postgraduate Project

Part Number: LP-MSPM0G3507

Tool/software:

Hello everyone,

I am working on a project for my postgraduate studies and I've encountered an issue with part of the code. The goal is to trigger a 12-bit ADC through a comparator (COMP) using an external pin. The values captured by the ADC should be stored in an array and later sent to a CSV file.

However, I am having trouble with triggering the ADC, both via interruption and 'event'. The ADC only executes once and then the entire code stops. Below is the code I am using:

const ADC12  = scripting.addModule("/ti/driverlib/ADC12", {}, false);
const ADC121 = ADC12.addInstance();
const Board  = scripting.addModule("/ti/driverlib/Board");
const COMP   = scripting.addModule("/ti/driverlib/COMP", {}, false);
const COMP1  = COMP.addInstance();
const GPIO   = scripting.addModule("/ti/driverlib/GPIO", {}, false);
const GPIO1  = GPIO.addInstance();
const GPIO2  = GPIO.addInstance();
const GPIO3  = GPIO.addInstance();
const GPIO4  = GPIO.addInstance();
const GPIO5  = GPIO.addInstance();
const OPA    = scripting.addModule("/ti/driverlib/OPA", {}, false);
const OPA1   = OPA.addInstance();
const SYSCTL = scripting.addModule("/ti/driverlib/SYSCTL");
const VREF   = scripting.addModule("/ti/driverlib/VREF");

/**
 * Write custom configuration values to the imported modules.
 */
const divider9       = system.clockTree["UDIV"];
divider9.divideValue = 2;

const gate7  = system.clockTree["MFCLKGATE"];
gate7.enable = true;

const gate8  = system.clockTree["MFPCLKGATE"];
gate8.enable = true;

const multiplier2         = system.clockTree["PLL_QDIV"];
multiplier2.multiplyValue = 5;

const mux8       = system.clockTree["HSCLKMUX"];
mux8.inputSelect = "HSCLKMUX_SYSPLL0";

const oscillator2           = system.clockTree["SYSOSC"];
oscillator2.enableSYSOSCFCL = true;

ADC121.$name              = "ADC12_0";
ADC121.adcMem0vref        = "VREF";
ADC121.enabledInterrupts  = ["DL_ADC12_INTERRUPT_MEM0_RESULT_LOADED"];
ADC121.sampleTime0        = "250 ns";
ADC121.sampleTime1        = "250 ns";
ADC121.adcMem0bcsen       = true;
ADC121.sampClkSrc         = "DL_ADC12_CLOCK_ULPCLK";
ADC121.adcMem0chansel     = "DL_ADC12_INPUT_CHAN_13";
ADC121.enableFIFO         = true;
ADC121.repeatMode         = true;
ADC121.peripheral.$assign = "ADC0";

Board.InitPriority11 = "/ti/driverlib/PWM";
Board.InitPriority13 = "/ti/driverlib/QEI";
Board.InitPriority14 = "/ti/driverlib/CAPTURE";
Board.InitPriority12 = "/ti/driverlib/COMPARE";
Board.InitPriority5  = "/ti/driverlib/GPIO";
Board.InitPriority1  = "/ti/driverlib/VREF";
Board.InitPriority3  = "/ti/driverlib/COMP";

COMP1.channelEnable                  = ["POS"];
COMP1.vSource                        = "DL_COMP_REF_SOURCE_VREF_DAC";
COMP1.controlSelect                  = "DL_COMP_DAC_CONTROL_SW";
COMP1.enableOutputFilter             = true;
COMP1.$name                          = "COMP";
COMP1.outputEnable                   = true;
COMP1.enabledInterrupts              = ["DL_COMP_INTERRUPT_OUTPUT_EDGE"];
COMP1.posChannel                     = "DL_COMP_IPSEL_CHANNEL_1";
COMP1.interruptPriority              = "0";
COMP1.peripheral.$assign             = "COMP1";
COMP1.peripheral.compPinOut.$assign  = "PA3";
COMP1.peripheral.compPinPos1.$assign = "PB24";
COMP1.compPinOutConfig.$name         = "ti_driverlib_gpio_GPIOPinGeneric2";
COMP1.compPinPos1Config.$name        = "ti_driverlib_gpio_GPIOPinGeneric3";

GPIO1.$name                          = "GPIO_PB6";
GPIO1.port                           = "PORTB";
GPIO1.portSegment                    = "Lower";
GPIO1.associatedPins[0].initialValue = "SET";
GPIO1.associatedPins[0].$name        = "USER_PB6";
GPIO1.associatedPins[0].assignedPin  = "6";
GPIO1.associatedPins[0].pin.$assign  = "PB6";

GPIO2.port                           = "PORTB";
GPIO2.portSegment                    = "Lower";
GPIO2.$name                          = "GPIO_PB7";
GPIO2.associatedPins[0].initialValue = "SET";
GPIO2.associatedPins[0].$name        = "USER_PB7";
GPIO2.associatedPins[0].assignedPin  = "7";
GPIO2.associatedPins[0].pin.$assign  = "PB7";

GPIO3.port                           = "PORTB";
GPIO3.portSegment                    = "Lower";
GPIO3.$name                          = "GPIO_PB8";
GPIO3.associatedPins[0].initialValue = "SET";
GPIO3.associatedPins[0].$name        = "USER_PB8";
GPIO3.associatedPins[0].assignedPin  = "8";

GPIO4.port                                = "PORTB";
GPIO4.$name                               = "GPIO_green";
GPIO4.portSegment                         = "Upper";
GPIO4.associatedPins[0].initialValue      = "SET";
GPIO4.associatedPins[0].$name             = "USER_green";
GPIO4.associatedPins[0].launchPadShortcut = "LED2GreenEn";

GPIO5.port                                = "PORTB";
GPIO5.portSegment                         = "Upper";
GPIO5.$name                               = "GPIO_blue";
GPIO5.associatedPins[0].initialValue      = "SET";
GPIO5.associatedPins[0].$name             = "USER_blue";
GPIO5.associatedPins[0].launchPadShortcut = "LED2BlueEn";
GPIO5.associatedPins[0].pin.$assign       = "PB22";

OPA1.$name                        = "OPA_0";
OPA1.cfg0PSELChannel              = "IN0_POS";
OPA1.cfg0MSELChannel              = "GND";
OPA1.cfg0Chop                     = "ADC_AVERAGING";
OPA1.advBW                        = "HIGH";
OPA1.cfg0NSELChannel              = "RBOT";
OPA1.advRRI                       = true;
OPA1.cfg0OutputPin                = "ENABLED";
OPA1.peripheral.$assign           = "OPA0";
OPA1.peripheral.In0PosPin.$assign = "PA26";
OPA1.peripheral.OutPin.$assign    = "PA22";
OPA1.In0PosPinConfig.$name        = "ti_driverlib_gpio_GPIOPinGeneric0";
OPA1.OutPinConfig.$name           = "ti_driverlib_gpio_GPIOPinGeneric4";

SYSCTL.forceDefaultClkConfig = true;
SYSCTL.clockTreeEn           = true;

VREF.advClockConfigEnable          = true;
VREF.advClkSrc                     = "DL_VREF_CLOCK_BUSCLK";
VREF.checkVREFReady                = true;
VREF.peripheral.$assign            = "VREF";
VREF.peripheral.vrefPosPin.$assign = "PA23";
VREF.vrefPosPinConfig.$name        = "ti_driverlib_gpio_GPIOPinGeneric1";

Board.peripheral.$suggestSolution            = "DEBUGSS";
Board.peripheral.swclkPin.$suggestSolution   = "PA20";
Board.peripheral.swdioPin.$suggestSolution   = "PA19";
GPIO3.associatedPins[0].pin.$suggestSolution = "PB8";
GPIO4.associatedPins[0].pin.$suggestSolution = "PB27";

#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <stdbool.h>
#include "ti/driverlib/dl_adc12.h"
#include "ti/driverlib/dl_gpio.h"
#include "ti_msp_dl_config.h"
#include "sys/_stdint.h"
#include "ti/driverlib/m0p/dl_core.h"

#define COMP_INST_REF_VOLTAGE_mV (3300)
#define COMP_INST_DAC8_OUTPUT_VOLTAGE_mV (50)

const uint16_t ADC_RESOLUTION = 12;
const uint16_t ARRAY_SIZE = 0x01 << ADC_RESOLUTION;

volatile bool gCheckADC = false;
volatile bool start = false;
volatile uint16_t gADCResult = 0;

uint8_t dacValue = 0;
uint32_t amostras[ARRAY_SIZE];

uint32_t count = 0;
uint32_t NUM_AMOSTRAS = 10000;

//-----------------------------------------------------------------------------------------------------------------------------
// Function to Save Data to CSV:
void salvarAmostrasCSV(const char *nomeArquivo, uint32_t amostras[], uint16_t numAmostras) {
    // Construa o caminho absoluto
    const char *caminhoAbsoluto = "C:/Users/verga/OneDrive/Desktop/ADC_resultados/julho/amostra.csv";

    FILE *file = fopen(caminhoAbsoluto, "w");

    if (file == NULL){
        printf("Error opening the file.\n");
        return;
    }

    printf("File opened successfully. Saving data...\n");

    fprintf(file, "Valor ADC,Ocorrencias\n");
            for(int i = 0; i < ARRAY_SIZE; i++){
                fprintf(file, "%d,%d\n", i, amostras[i]);
        }

    fclose(file);
    printf("Data successfully saved to CSV file.\n");
}

//-----------------------------------------------------------------------------------------------------------------------------
// Function to clear array
void limparArray(uint32_t amostras[], uint32_t tamanho) {
    memset(amostras, 0, tamanho * sizeof(uint32_t));
}

//-----------------------------------------------------------------------------------------------------------------------------
// Configures the comparator and enables DAC and related interrupts
void COMP() {
    dacValue = (COMP_INST_DAC8_OUTPUT_VOLTAGE_mV * 255) / COMP_INST_REF_VOLTAGE_mV;     // Calculate the DAC value based on the configured voltage
    DL_COMP_setDACCode0(COMP_INST, dacValue);                                           // Configures the comparator DAC
    DL_COMP_enable(COMP_INST);                                                          // Enable the comparator
    DL_COMP_enableInterrupt(COMP_INST, DL_COMP_INTERRUPT_OUTPUT_EDGE);                  // Enable comparator interrupts
    NVIC_EnableIRQ(COMP_INST_INT_IRQN);                                                 // Enable interrupt on NVIC
    //printf("Comparator configured and interrupt enabled. (COMP)\n");
}

//-----------------------------------------------------------------------------------------------------------------------------
// Delay function in clock cycle
void delay_cycles(uint32_t cycles) {
    while (cycles > 0) {
        __asm(" nop");
        cycles--;
    }
}

//-----------------------------------------------------------------------------------------------------------------------------
// ADC reading function
void readADC() {
    gADCResult = 0;
    DL_ADC12_startConversion(ADC12_0_INST);                                             // ADC activation
    DL_GPIO_setPins((GPIOB), GPIO_PB7_USER_PB7_PIN);                                    // oscilloscope visualization control
    gADCResult = DL_ADC12_getMemResult(ADC12_0_INST, DL_ADC12_MEM_IDX_0) & 0xFFF;
}


//-----------------------------------------------------------------------------------------------------------------------------
// ADC recording function:
void recordADC() {
    amostras[gADCResult]++;                                                             // Increments the occurrence of the ADC value in the array
    DL_GPIO_clearPins((GPIOB), GPIO_PB7_USER_PB7_PIN);                                  // oscilloscope visualization control
    DL_GPIO_clearPins((GPIOB), GPIO_PB6_USER_PB6_PIN);                                  // reset do opengamma
    printf("ADC lido: %d\n", gADCResult);
    delay_cycles(20);                                                                   // delay in clock cycles
    DL_GPIO_setPins((GPIOB), GPIO_PB6_USER_PB6_PIN);                                    // reset do opengamma
    start = false;   
    gCheckADC = false;
}

//-----------------------------------------------------------------------------------------------------------------------------
// Comparator Interrupt Handler:
void GROUP1_IRQHandler(void) {
    if (DL_COMP_getPendingInterrupt(COMP_INST) == DL_COMP_IIDX_OUTPUT_EDGE) {           // Checks whether the interrupt was caused by a rising edge
        start = true;                                                                   
        DL_COMP_clearInterruptStatus(COMP_INST, DL_COMP_INTERRUPT_OUTPUT_EDGE);         // Clears comparator interrupt
    }
}

//-----------------------------------------------------------------------------------------------------------------------------
// Interrupt handler for the ADC
void ADC12_0_INST_IRQHandler(void) {
    if (DL_ADC12_getPendingInterrupt(ADC12_0_INST) == DL_ADC12_IIDX_MEM0_RESULT_LOADED) {
        gCheckADC = true;
        DL_ADC12_clearInterruptStatus(ADC12_0_INST, DL_ADC12_INTERRUPT_MEM0_RESULT_LOADED); // Clears ADC interrupt
    }
}
//-----------------------------------------------------------------------------------------------------------------------------
// Função principal que configura o sistema
int main(void) {
    SYSCFG_DL_init();
    NVIC_EnableIRQ(COMP_INST_INT_IRQN);
    NVIC_EnableIRQ(ADC12_0_INST_INT_IRQN);

    COMP();
    limparArray(amostras, ARRAY_SIZE);

    printf("Sistema inicializado\n");


    while(count < NUM_AMOSTRAS){
        while (!start);             // Wait for the comparator to interrupt       
        readADC();
        recordADC();
        count++;
        printf("count: %d\n", count);
    }

    salvarAmostrasCSV("amostras.csv", amostras, ARRAY_SIZE);
    printf("FIM! \n");
    return 0; 
}

Issue Faced:

  • The ADC is triggered only once and does not continue as expected.

If anyone could provide guidance or support on how to resolve this issue, I would greatly appreciate it.

Thank you in advance for your help!

  • Hi Diego,

    When you stop the program with a debugger, where are you in the code? Place a breakpoint at 134 you can catch after the first read and check to make sure the ADC configurations is as expected.

    Regards,
    Luke

  • Hello Lucas,

    before starting before starting

    The program gets stuck (in a loop) at line 133, waiting for the 'start' value to return to '1'.
     before the first pass through while

    The first time it is triggered and it enters the functions "readADC" and "recordADC" normally.

    When it returns to make a second pass through the 'while' loop, the value of 'start' is '0' and does not return to '1'.

     second passed by while

    Could there be something wrong that I did in the comparator configuration?

    Attached is an image of the comparator configuration screen in CCS Theia.

    Thank you very much for the help.

  • Hi Diego,

    The comparator portion doesn't look wrong to me at first glance. What's your input signal? You have a trigger on the rising or falling edge, so what I would expect is anytime you cross the 50mV mark (based on line 13) you should get a trigger on your comparator. You can place a breakpoint in your COMP ISR and then switch your COMPIN+ signal to verify you are getting a trigger on the rising and falling edges.

    Regards,
    Luke