First I want to start by apologizing that I'm a newbie. I'm still learning from example codes and all that stuff. I have already watched all the ADC-related articles on the forum but there don't seem to have anyone having this problem. So, I'm trying to use ADC combined with SCTimer. The idea is that the SCTimer will generate a 100% duty cycle PWM while ADC reading the value. Once the ADC value reached the high threshold (I didn't set the low threshold), it will trigger threshold interrupt in which I set the SCTimer to change the duty cycle to 30%.
After multiple test runs, the ADC could successfully read the value, and I could see from the console that the "Threshold Range" shift from 0x0 to 0x2, which means the value is higher than the high threshold. The PWM, however, still stayed the same at 100% duty cycle, and there was no ADC threshold event shown on the console as well.
I then used ADC example to test the threshold interrupt, adding simple LED toggle in the threshold interrupt handler as below. The outcome was always the same. The LED didn't react, and there was no ADC threshold event shown on the console though the threshold range showed that the value already passed the threshold.
#include "board.h"
#include <stdio.h>
/*****************************************************************************
* Private types/enumerations/variables
****************************************************************************/
static volatile int ticks;
static bool sequenceComplete, thresholdCrossed;
#define TICKRATE_HZ (100) /* 100 ticks per second */
#if defined(BOARD_NXP_LPCXPRESSO_54102)
#define BOARD_ADC_CH 8
#else
#warning "Using ADC channel 8 for this example, please select for your board"
#define BOARD_ADC_CH 8
#endif
/*****************************************************************************
* Public types/enumerations/variables
****************************************************************************/
/*****************************************************************************
* Private functions
****************************************************************************/
/*****************************************************************************
* Public functions
****************************************************************************/
/**
* @brief Handle interrupt from SysTick timer
* @return Nothing
*/
void SysTick_Handler(void)
{
static uint32_t count;
/* Every 1/2 second */
count++;
if (count >= (TICKRATE_HZ / 2)) {
count = 0;
/* Manual start for ADC conversion sequence A */
Chip_ADC_StartSequencer(LPC_ADC, ADC_SEQA_IDX);
}
}
/* SEQ-A interrupt handler */
void ADC_SEQA_IRQHandler(void)
{
uint32_t pending;
/* Get pending interrupts */
pending = Chip_ADC_GetFlags(LPC_ADC);
/* Sequence A completion interrupt */
if (pending & ADC_FLAGS_SEQA_INT_MASK) {
sequenceComplete = true;
}
/* Clear any pending interrupts */
Chip_ADC_ClearFlags(LPC_ADC, ADC_FLAGS_SEQA_INT_MASK);
}
/* ADC threashold interrupt handler */
void ADC_THCMP_IRQHandler(void)
{
uint32_t pending;
/* Get pending interrupts */
pending = Chip_ADC_GetFlags(LPC_ADC);
/* Threshold crossing interrupt on ADC input channel */
if (pending & ADC_FLAGS_THCMP_MASK(BOARD_ADC_CH)) {
thresholdCrossed = true;
Board_LED_Toggle(0);
}
/* Clear any pending interrupts */
Chip_ADC_ClearFlags(LPC_ADC, ADC_FLAGS_THCMP_MASK(BOARD_ADC_CH));
}
/* main function (C entry point) */
int main(void)
{
int loop = 1; /* Prevents unreachable statement warning */
uint32_t rawSample;
int j;
SystemCoreClockUpdate();
Board_Init();
DEBUGSTR("ADC sequencer demo\r\n");
//Set the state of a board LED to on or off
Board_LED_Set(0,false);
/* Setup ADC for 12-bit mode and normal power */
Chip_ADC_Init(LPC_ADC, (ADC_CR_RESOL(3) | ADC_CR_TSAMP(ADC_TSAMP_7CLK5)));
/* FIXME: Enable ADC, should be at least 10mS after ADC is powered up */
LPC_ADC->STARTUP = 0x1;
LPC_ADC->STARTUP = 0x3; /* Dummy calibration */
/* Need to do a calibration after initialization and trim */
Chip_ADC_Calibration(LPC_ADC);
/* Setup for maximum ADC clock rate using sycnchronous clocking */
Chip_ADC_SetClockRate(LPC_ADC, ADC_MAX_SAMPLE_RATE);
/* Optionally, you can setup the ADC to use asycnchronous clocking mode.
To enable this, mode use 'LPC_ADC->CTRL |= ADC_CR_ASYNMODE;'.
In asycnchronous clocking mode mode, the following functions are
used to set and determine ADC rates:
Chip_Clock_SetADCASYNCSource();
Chip_Clock_SetADCASYNCClockDiv();
Chip_Clock_GetADCASYNCRate();
clkRate = Chip_Clock_GetADCASYNCRate() / Chip_Clock_GetADCASYNCClockDiv; */
/* Setup sequencer A for ADC channel 0, EOS interrupt */
#if defined(BOARD_NXP_LPCXPRESSO_54102)
/* Setup a sequencer to do the following:
Perform ADC conversion of ADC channels 0 and 8 only */
Chip_ADC_SetupSequencer(LPC_ADC, ADC_SEQA_IDX, (ADC_SEQ_CTRL_CHANSEL(BOARD_ADC_CH) |
ADC_SEQ_CTRL_CHANSEL(BOARD_ADC_CH) | ADC_SEQ_CTRL_MODE_EOS));
/* ADC input 8 is on PIO0_12 mapped to FUNC2 */
Chip_IOCON_PinMuxSet(LPC_IOCON, 0, 12, (IOCON_FUNC3 | IOCON_MODE_INACT |
IOCON_ANALOG_EN));
#endif
/* Setup threshold 0 low and high values to about 25% and 75% of max */
//Chip_ADC_SetThrLowValue(LPC_ADC, 0, 0xf50); // ((1 * 0xFFF) / 4));
Chip_ADC_SetThrHighValue(LPC_ADC, 0, 0xf70);// ((3 * 0xFFF) / 4));
/* Clear all pending interrupts */
Chip_ADC_ClearFlags(LPC_ADC, Chip_ADC_GetFlags(LPC_ADC));
/* Enable ADC overrun and sequence A completion interrupts */
Chip_ADC_EnableInt(LPC_ADC, (ADC_INTEN_SEQA_ENABLE | ADC_INTEN_OVRRUN_ENABLE));
/* Use threshold 0 for ADC channel and enable threshold interrupt mode for
channel as crossing */
Chip_ADC_SelectTH0Channels(LPC_ADC, ADC_THRSEL_CHAN_SEL_THR1(BOARD_ADC_CH));
Chip_ADC_SetThresholdInt(LPC_ADC, BOARD_ADC_CH, ADC_INTEN_THCMP_CROSSING);
/* Enable ADC NVIC interrupt */
NVIC_EnableIRQ(ADC_SEQA_IRQn);
NVIC_EnableIRQ(ADC_THCMP_IRQn);
/* Enable sequencer */
Chip_ADC_EnableSequencer(LPC_ADC, ADC_SEQA_IDX);
SysTick_Config(SystemCoreClock / TICKRATE_HZ);
/* Endless loop */
while (loop) {
/* Sleep until something happens */
__WFI();
if (thresholdCrossed) {
thresholdCrossed = false;
DEBUGSTR("********ADC threshold event********\r\n");
}
/* Is a conversion sequence complete? */
if (sequenceComplete) {
sequenceComplete = false;
/* Get raw sample data for channels 0-11 */
for (j = 0; j < 12; j++) {
rawSample = Chip_ADC_GetDataReg(LPC_ADC, j);
/* Show some ADC data */
if ((rawSample & (ADC_DR_OVERRUN | ADC_SEQ_GDAT_DATAVALID)) != 0) {
DEBUGOUT("Sample value = 0x%x (Data sample %d)\r\n", ADC_DR_RESULT(rawSample), j);
DEBUGOUT("Threshold range = 0x%x\r\n", ADC_DR_THCMPRANGE(rawSample));
DEBUGOUT("Threshold cross = 0x%x\r\n", ADC_DR_THCMPCROSS(rawSample));
}
}
DEBUGOUT("Overrun = %d\r\n", ((rawSample & ADC_DR_OVERRUN) != 0));
DEBUGOUT("Data valid = %d\r\n", ((rawSample & ADC_SEQ_GDAT_DATAVALID) != 0));
DEBUGSTR("\r\n");
}
}
/* Should not run to here */
return 0;
}
Thanks
Solved! Go to Solution.
Hello curryhuang3627,
After I checked your question and code, I think you need configure threshold comparison interrupt to
outside threshold, not crossing threshold:
Regards,
Alice
Hello curryhuang3627,
After I checked your question and code, I think you need configure threshold comparison interrupt to
outside threshold, not crossing threshold:
Regards,
Alice
Thanks for the quick reply.
I think "outside threshold" might be the solution to my problem but I'm still having a hard time understanding the difference between the two. To me, I feel like they were saying the same thing.
How do you define "threshold crossing" and what do you expect to see if you configure this register?
sorry to bother you.
Hello ,
In my opinion, "crossing threshold " option means when ADC data just equal to the threadold.
Regards,
Alice
Thanks for the timely help.
I owe you a big one.