Setting Different DAC Voltage Level for Rising and Falling Edge of Analog Comparator

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Setting Different DAC Voltage Level for Rising and Falling Edge of Analog Comparator

1,793 Views
arun07
Contributor III

Hello Everyone,

I am working MKE15Z256 micro-controller and using the Analog Comparator module for some purpose.

I am using the "acmp_interrupt" example for demo purpose, in this example DAC is configured to "Half of Reference Voltage"

/* Configure DAC. */
    dacConfigStruct.referenceVoltageSource = kACMP_VrefSourceVin1;
    dacConfigStruct.DACValue               = 0x7FU; /* Half of referene voltage. */
#if defined(FSL_FEATURE_ACMP_HAS_C1_DACOE_BIT) && (FSL_FEATURE_ACMP_HAS_C1_DACOE_BIT == 1U)
    dacConfigStruct.enableOutput = true;
#endif /* FSL_FEATURE_ACMP_HAS_C1_DACOE_BIT */
#if defined(FSL_FEATURE_ACMP_HAS_C1_DMODE_BIT) && (FSL_FEATURE_ACMP_HAS_C1_DMODE_BIT == 1U)
    dacConfigStruct.workMode = kACMP_DACWorkLowSpeedMode;
#endif /* FSL_FEATURE_ACMP_HAS_C1_DMODE_BIT */
    ACMP_SetDACConfig(DEMO_ACMP_BASEADDR, &dacConfigStruct);

 

Here, the DAC voltage is same for Rising Edge and Falling Edge. Is there a way to configure the DAC voltage different for rising and falling edge?

Let's say my signal is a triangular waveform, and the frequency can vary from 25Hz to 100Hz, and voltage range of this signal is from 0V to 4V.

I want to generate rising edge interrupt at 2.5V but falling edge interrupt at 1.5V.

Right now I am planning to configure DAC for 2.5V and enabled only rising interrupt and when this is received, I will re-configure the module with DAC voltage 1.5V and falling interrupt. But reinitializing the DAC or/CMP module again, looks like not a good idea to me. Is there some better way?

Labels (1)
Tags (1)
0 Kudos
6 Replies

1,744 Views
arun07
Contributor III

Hi @jingpan 

As mentioned above in the post, I implemented the same in software and tried to test but it doesn't work.

The following is the program (I used acmp_interrupt program and modified it little but to suit my requirements)

 

#include "fsl_acmp.h"
#include "fsl_debug_console.h"
#include "pin_mux.h"
#include "clock_config.h"
#include "board.h"

/*******************************************************************************
 * Definitions
 ******************************************************************************/
#define DEMO_ACMP_BASEADDR         CMP0
#define DEMO_ACMP_USER_CHANNEL     0U
#define DEMO_ACMP_IRQ_ID           CMP0_IRQn
#define DEMO_ACMP_IRQ_HANDLER_FUNC CMP0_IRQHandler
#define LED_INIT()                 LED_GREEN1_INIT(LOGIC_LED_OFF)
#define LED_ON()                   LED_GREEN1_ON()
#define LED_OFF()                  LED_GREEN1_OFF()
#define RISING_THRESHOLD           103u   // 2V
#define FALLING_THRESHOLD          51u    // 1V

/*******************************************************************************
 * Prototypes
 ******************************************************************************/

/*******************************************************************************
 * Variables
 ******************************************************************************/
volatile uint32_t g_acmpOutputRising  = 0U;
volatile uint32_t g_acmpOutputFalling = 0U;
volatile uint8_t g_edge = 0u;
volatile uint32_t rising_error = 0u;
volatile uint32_t falling_error = 0u;
acmp_config_t acmpConfigStruct;
acmp_channel_config_t channelConfigStruct;
acmp_dac_config_t dacConfigStruct;

/*******************************************************************************
 * Code
 ******************************************************************************/
static void Custom_ACMP_Init( void );
static void Custom_ACMP_ReInit( uint8_t edge_type );

void DEMO_ACMP_IRQ_HANDLER_FUNC(void)
{
  uint32_t statusFlags = 0u;
  statusFlags = ACMP_GetStatusFlags(DEMO_ACMP_BASEADDR);
  ACMP_ClearStatusFlags(DEMO_ACMP_BASEADDR, statusFlags);
    
  if( g_edge == 0u )
  {
    if ((kACMP_OutputAssertEventFlag == (statusFlags & kACMP_OutputAssertEventFlag)) &&
        (kACMP_OutputRisingEventFlag == (statusFlags & kACMP_OutputRisingEventFlag)))
    {
      g_acmpOutputRising = 1U;
    }
    else
    {
      rising_error++;
    }
    // Reconfigure
    Custom_ACMP_ReInit(1);
    g_edge = 1u;
  }
  else if( g_edge == 1u )
  {
    if ((kACMP_OutputAssertEventFlag != (statusFlags & kACMP_OutputAssertEventFlag)) &&
             (kACMP_OutputFallingEventFlag == (statusFlags & kACMP_OutputFallingEventFlag)))
    {
      g_acmpOutputFalling = 1U;
    }
    else
    {
      falling_error++;
    }
    Custom_ACMP_ReInit(0);
    g_edge = 0u;
  }
  SDK_ISR_EXIT_BARRIER;
}

/*!
 * @brief Main function
 */
int main(void)
{
  BOARD_InitBootPins();
  BOARD_InitBootClocks();
  BOARD_InitDebugConsole();
  LED_INIT();
  LED_OFF();
  
  Custom_ACMP_Init();

  PRINTF("The example compares analog input to the reference DAC output(CMP negative port).\r\n");
  PRINTF("The LED will be turned ON/OFF when the analog input is HIGHER/LOWER than the DAC output.\r\n");
  PRINTF("Change the analog input voltage to see the LED status.\r\n");

  while (true)
  {
    /* Check the comparison result and toggle the LED according to the result. */
    if (g_acmpOutputRising)
    {
      g_acmpOutputRising = 0U;
      LED_ON();
      PRINTF("The analog input is HIGHER than DAC output\r\n");
    }
    else if (g_acmpOutputFalling)
    {
      g_acmpOutputFalling = 0U;
      LED_OFF();
      PRINTF("The analog input is LOWER than DAC output\r\n");
    }
    else
    {
      /* Unknown status. */
    }
  }
}

static void Custom_ACMP_Init( void )
{
  ACMP_GetDefaultConfig(&acmpConfigStruct);
  acmpConfigStruct.hysteresisMode = kACMP_HysteresisLevel3;
  ACMP_Init(DEMO_ACMP_BASEADDR, &acmpConfigStruct);
  
  channelConfigStruct.positivePortInput = kACMP_PortInputFromMux;
  channelConfigStruct.negativePortInput = kACMP_PortInputFromDAC;
  channelConfigStruct.minusMuxInput     = 0U; /* Dummy channel. */
  channelConfigStruct.plusMuxInput      = DEMO_ACMP_USER_CHANNEL;
  ACMP_SetChannelConfig(DEMO_ACMP_BASEADDR, &channelConfigStruct);

  /* Configure DAC. */
  dacConfigStruct.referenceVoltageSource = kACMP_VrefSourceVin1;
  dacConfigStruct.DACValue               = RISING_THRESHOLD;  //0x7FU; /* Half of referene voltage. */
#if defined(FSL_FEATURE_ACMP_HAS_C1_DACOE_BIT) && (FSL_FEATURE_ACMP_HAS_C1_DACOE_BIT == 1U)
  dacConfigStruct.enableOutput = true;
#endif /* FSL_FEATURE_ACMP_HAS_C1_DACOE_BIT */
#if defined(FSL_FEATURE_ACMP_HAS_C1_DMODE_BIT) && (FSL_FEATURE_ACMP_HAS_C1_DMODE_BIT == 1U)
  dacConfigStruct.workMode = kACMP_DACWorkLowSpeedMode;
#endif /* FSL_FEATURE_ACMP_HAS_C1_DMODE_BIT */
  ACMP_SetDACConfig(DEMO_ACMP_BASEADDR, &dacConfigStruct);

  /* Enable the interrupts. */
  // ACMP_EnableInterrupts(DEMO_ACMP_BASEADDR, kACMP_OutputRisingInterruptEnable | kACMP_OutputFallingInterruptEnable);
  ACMP_EnableInterrupts(DEMO_ACMP_BASEADDR, kACMP_OutputRisingInterruptEnable );
  EnableIRQ(DEMO_ACMP_IRQ_ID);

  ACMP_Enable(DEMO_ACMP_BASEADDR, true);
}

static void Custom_ACMP_ReInit( uint8_t edge_type )
{
  ACMP_Enable(DEMO_ACMP_BASEADDR, false);
  /* Configure DAC. */
  if( edge_type == 0u )
  {
    dacConfigStruct.DACValue = RISING_THRESHOLD;
  }
  else
  {
    dacConfigStruct.DACValue = FALLING_THRESHOLD;
  }
  ACMP_SetDACConfig(DEMO_ACMP_BASEADDR, &dacConfigStruct);

  /* Enable the interrupts. */
  if( edge_type == 0u )
  {
    ACMP_DisableInterrupts(DEMO_ACMP_BASEADDR, kACMP_OutputFallingInterruptEnable);
    ACMP_EnableInterrupts(DEMO_ACMP_BASEADDR, kACMP_OutputRisingInterruptEnable);
  }
  else
  {
    ACMP_DisableInterrupts(DEMO_ACMP_BASEADDR, kACMP_OutputRisingInterruptEnable);
    ACMP_EnableInterrupts(DEMO_ACMP_BASEADDR, kACMP_OutputFallingInterruptEnable);
  }
  
  EnableIRQ(DEMO_ACMP_IRQ_ID);

  ACMP_Enable(DEMO_ACMP_BASEADDR, true);
}

 

The flow is as below.

  • At Power-Up, configure the CMP for Rising Edge
  • When Rising Edge is received, Disable the CMP
  • Update the DAC value for Falling Edge
  • Enable the Falling Interrupt and Disable the Rising Interrupt
  • Repeat the same steps for Rising Edge

But when I do so, the first rising edge is okay, but as soon as I tried to change the DAC value, and reconfigure the module, the next interrupt occurs immediately.

After debugging I found the following scenarios.

I disabled the Comparator Module, before updating the DAC value, and here CFF bit is set (my understanding is, since we disabled the module, Comparator Output changes from High -> Low, hence this happens)

test2.JPG

After updating the DAC value for falling edge, I enabled the Comparator, and due to the my setup position, COUT is now 1 again, and hence CFR bit is also set.

Test3.JPG

And this messed up by simple state-machine.

test.png

But if I run my code by commenting the line ACMP_Enable(DEMO_ACMP_BASEADDR, false);, everything works fine, for obvious reason.

Can you please suggest, should I proceed without disabling the module?

The reason I disabled the module is because I am changing the DAC values and enabling only one type of interrupt at a time.

 

0 Kudos

1,721 Views
jingpan
NXP TechSupport
NXP TechSupport

Hi @arun07 ,

Yes, when you enable the  comparator, it will perform a comparing. So, even you clear CFR and CFF in Custom_ACMP_ReInit, CFR or CFF will set after comparator enable. I delete the disable comparator command, then it works fine.

 

Regards,

Jing

0 Kudos

1,692 Views
arun07
Contributor III

Thanks @jingpan 

So if we don't disabled the comparator module, it works fine.

At the moment I am using a Potentiometer and rotating it manually, even I moved it very fast and everything was fine.

But when I applied my actual signal, which will looks like this.

Signal.JPG

I found that the variables in the else part of the interrupt handler i.e. "rising_error" and "falling_error" keeps on incrementing sometimes, not so fast but the pattern is uneven.

Does this means that the Comparator is not so fast enough to handle this type of signals, my signal frequency is 50Hz and can go till 60Hz, but as of now I am just testing with 50Hz.

Can you please suggest something here?

Thanks in advance.

0 Kudos

1,787 Views
jingpan
NXP TechSupport
NXP TechSupport

Hi @arun07 ,

One comparator has only one comparation voltage. If you want to compare two voltage, you can use two comparator.

 

Regards,

Jing

1,780 Views
arun07
Contributor III

Thanks @jingpan for your response

If I have to use two comparators then I have to provide the external signal to both comparators, which is not possible in my project at the moment.

Can I do like below.

  • At initialization configure the Comparator module for interrupt on rising edge when input voltage is greater than 2.5V (from DAC)
  • When I received the rising interrupt, reconfigure the module to generate falling edge interrupt, when voltage is greater than 1.5V (from DAC)
  • When I received the falling edge interrupt, reconfigure the module to generate rising edge interrupt when DAC input voltage is greater than 2.5 (from DAC)

If I do it like this, do you see any risk here or any other point which you wanted to mention?

Tags (1)
0 Kudos

1,765 Views
jingpan
NXP TechSupport
NXP TechSupport

Hi @arun07 ,

Yes, it sounds fine.

 

Regards,

Jing

0 Kudos