LPC865ADC Initialization problem

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

LPC865ADC Initialization problem

440 Views
rmaier
Contributor III

Hello,

 

We are having trouble getting a software-triggered ADC read on the LPC865M201. The goal is to read something from ch 7 on PIO0_19. This is all started by calling init_adc(). The target is using an external OSC @ 16MHz with a main clock running at 48 MHz. The ADC_DAT_DATAVALID_MASK is always 0. Below is code taken from the SDK. Any idea where this is going wrong?

 

#define DEMO_ADC_BASE                  ADC0
#define DEMO_ADC_SAMPLE_CHANNEL_NUMBER 7U
#define DEMO_ADC_CLOCK_SOURCE          kCLOCK_Fro
#define DEMO_ADC_CLOCK_DIVIDER         1U

/*!
 * @brief Define selection of polarity of selected input trigger for conversion sequence.
 */
typedef enum _adc_trigger_polarity
{
    kADC_TriggerPolarityNegativeEdge = 0U, /*!< A negative edge launches the conversion sequence on the trigger(s). */
    kADC_TriggerPolarityPositiveEdge = 1U, /*!< A positive edge launches the conversion sequence on the trigger(s). */
} adc_trigger_polarity_t;

/*!
 * @brief Define selection of conversion sequence's interrupt.
 */
typedef enum _adc_seq_interrupt_mode
{
    kADC_InterruptForEachConversion = 0U, /*!< The sequence interrupt/DMA trigger will be set at the end of each
                                               individual ADC conversion inside this conversion sequence. */
    kADC_InterruptForEachSequence = 1U,   /*!< The sequence interrupt/DMA trigger will be set when the entire set of
                                               this sequence conversions completes. */
} adc_seq_interrupt_mode_t;



/*!
 * @brief Define structure for configuring the block.
 */
typedef struct _adc_config
{
    uint32_t clockDividerNumber; /*!< This field is only available when using kADC_ClockSynchronousMode for "clockMode"
                                      field. The divider would be plused by 1 based on the value in this field. The
                                      available range is in 8 bits. */

} adc_config_t;

/*!
 * @brief Define structure for configuring conversion sequence.
 */
typedef struct _adc_conv_seq_config
{
    uint32_t channelMask; /*!< Selects which one or more of the ADC channels will be sampled and converted when this
             sequence is launched. The masked channels would be involved in current conversion
             sequence, beginning with the lowest-order. The available range is in 12-bit. */
    uint32_t triggerMask; /*!< Selects which one or more of the available hardware trigger sources will cause this
             conversion sequence to be initiated. The available range is 6-bit.*/
    adc_trigger_polarity_t triggerPolarity; /*!< Select the trigger to launch conversion sequence. */
    bool enableSyncBypass; /*!< To enable this feature allows the hardware trigger input to bypass synchronization
               flip-flop stages and therefore shorten the time between the trigger input signal and the
               start of a conversion. */
    bool enableSingleStep; /*!< When enabling this feature, a trigger will launch a single conversion on the next
               channel in the sequence instead of the default response of launching an entire sequence
               of conversions. */
    adc_seq_interrupt_mode_t interruptMode; /*!< Select the interrpt/DMA trigger mode. */
} adc_conv_seq_config_t;

adc_result_info_t adcResultInfoStruct;



/*!
 * brief Get the channel's ADC conversion completed under each conversion sequence.
 *
 * param base ADC peripheral base address.
 * param channel The indicated channel number.
 * param info Pointer to information structure, see to #adc_result_info_t;
 * retval true  The conversion result is ready.
 * retval false The conversion result is not ready yet.
 */
bool ADC_GetChannelConversionResult(ADC_Type* base, uint32_t channel, adc_result_info_t* info)
{
    uint32_t tmp32 = base->DAT[channel]; /* Read to clear the status. */
    bool ret = true;

    if (0U == (ADC_DAT_DATAVALID_MASK & tmp32))
    {
        ret = false;
    }

    info->result = (tmp32 & ADC_DAT_RESULT_MASK) >> ADC_DAT_RESULT_SHIFT;

    info->thresholdCompareStatus =
        (adc_threshold_compare_status_t)(uint32_t)((tmp32 & ADC_DAT_THCMPRANGE_MASK) >> ADC_DAT_THCMPRANGE_SHIFT);
    info->thresholdCorssingStatus =
        (adc_threshold_crossing_status_t)(uint32_t)((tmp32 & ADC_DAT_THCMPCROSS_MASK) >> ADC_DAT_THCMPCROSS_SHIFT);
    info->channelNumber = (tmp32 & ADC_DAT_CHANNEL_MASK) >> ADC_DAT_CHANNEL_SHIFT;
    info->overrunFlag = ((tmp32 & ADC_DAT_OVERRUN_MASK) == ADC_DAT_OVERRUN_MASK);

    return ret;
}

/*!
 * brief Get the global ADC conversion infomation of sequence A.
 *
 * param base ADC peripheral base address.
 * param info Pointer to information structure, see to #adc_result_info_t;
 * retval true  The conversion result is ready.
 * retval false The conversion result is not ready yet.
 */
bool ADC_GetConvSeqAGlobalConversionResult(ADC_Type* base, adc_result_info_t* info)
{
    uint32_t tmp32 = base->SEQ_GDAT[0]; /* Read to clear the status. */
    bool ret = true;

    if (0U == (ADC_SEQ_GDAT_DATAVALID_MASK & tmp32))
    {
        ret = false;
    }

    info->result = (tmp32 & ADC_SEQ_GDAT_RESULT_MASK) >> ADC_SEQ_GDAT_RESULT_SHIFT;
    info->thresholdCompareStatus = (adc_threshold_compare_status_t)(uint32_t)((tmp32 & ADC_SEQ_GDAT_THCMPRANGE_MASK) >>
        ADC_SEQ_GDAT_THCMPRANGE_SHIFT);
    info->thresholdCorssingStatus = (adc_threshold_crossing_status_t)(uint32_t)(
        (tmp32 & ADC_SEQ_GDAT_THCMPCROSS_MASK) >> ADC_SEQ_GDAT_THCMPCROSS_SHIFT);
    info->channelNumber = (tmp32 & ADC_SEQ_GDAT_CHN_MASK) >> ADC_SEQ_GDAT_CHN_SHIFT;
    info->overrunFlag = ((tmp32 & ADC_SEQ_GDAT_OVERRUN_MASK) == ADC_SEQ_GDAT_OVERRUN_MASK);

    return ret;
}


void init_adc()
{
    adc_config_t adcConfigStruct;
    adc_conv_seq_config_t adcConvSeqConfigStruct;

    uint32_t tmp32 = 0U;

    adcConfigStruct.clockDividerNumber = DEMO_ADC_CLOCK_DIVIDER;

    SYSCON->SYSAHBCLKCTRL0 turnon SYSCON_SYSAHBCLKCTRL0_ADC_MASK;

    /* Disable the interrupts. */
    ADC0->INTEN = 0U; /* Quickly disable all the interrupts. */

    /* Configure the ADC block. */
    tmp32 = ADC_CTRL_CLKDIV(adcConfigStruct.clockDividerNumber);

    ADC0->CTRL = tmp32;

    /* Enable channel DEMO_ADC_SAMPLE_CHANNEL_NUMBER's conversion in Sequence A. */

    adcConvSeqConfigStruct.channelMask =
        (1U << DEMO_ADC_SAMPLE_CHANNEL_NUMBER); /* Includes channel DEMO_ADC_SAMPLE_CHANNEL_NUMBER. */
    adcConvSeqConfigStruct.triggerMask = 0U;
    adcConvSeqConfigStruct.triggerPolarity = kADC_TriggerPolarityPositiveEdge;
    adcConvSeqConfigStruct.enableSingleStep = false;
    adcConvSeqConfigStruct.enableSyncBypass = false;
    adcConvSeqConfigStruct.interruptMode = kADC_InterruptForEachSequence;

    tmp32 = ADC_SEQ_CTRL_CHANNELS(adcConvSeqConfigStruct.channelMask) /* Channel mask. */
        | ADC_SEQ_CTRL_TRIGGER(adcConvSeqConfigStruct.triggerMask);       /* Trigger mask. */

    /* Polarity for tirgger signal. */
    switch (adcConvSeqConfigStruct.triggerPolarity)
    {
    case kADC_TriggerPolarityPositiveEdge:
        tmp32 |= ADC_SEQ_CTRL_TRIGPOL_MASK;
        break;
    default: /* kADC_TriggerPolarityNegativeEdge */
        break;
    }

    /* Bypass the clock Sync. */
    if (adcConvSeqConfigStruct.enableSyncBypass)
    {
        tmp32 |= ADC_SEQ_CTRL_SYNCBYPASS_MASK;
    }

    /* Interrupt point. */
    switch (adcConvSeqConfigStruct.interruptMode)
    {
    case kADC_InterruptForEachSequence:
        tmp32 |= ADC_SEQ_CTRL_MODE_MASK;
        break;
    default: /* kADC_InterruptForEachConversion */
        break;
    }

    /* One trigger for a conversion, or for a sequence. */
    if (adcConvSeqConfigStruct.enableSingleStep)
    {
        tmp32 |= ADC_SEQ_CTRL_SINGLESTEP_MASK;
    }

    ADC0->SEQ_CTRL[0] = tmp32;

    ADC0->SEQ_CTRL[0] |= ADC_SEQ_CTRL_SEQ_ENA_MASK;

    ADC0->SEQ_CTRL[0] |= ADC_SEQ_CTRL_START_MASK;

    while (!ADC_GetChannelConversionResult(DEMO_ADC_BASE, DEMO_ADC_SAMPLE_CHANNEL_NUMBER, &adcResultInfoStruct))
    {
    }
    ADC_GetConvSeqAGlobalConversionResult(DEMO_ADC_BASE, &adcResultInfoStruct);
}

 

0 Kudos
3 Replies

362 Views
rmaier
Contributor III

We do not have an eval board on hand. However, we did manage to figure this out.

Thanks,

Robert

0 Kudos

409 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi,

In the SDK package, there is an ADC example called lpc_adc_interrupt, I developed the code based on the example so that you can sample ADC_7 channel which is PIO0_19 pin.

xiangjun_rong_0-1695351000304.png

 

I changed the pin_mux.c with the code:

void BOARD_InitPins(void)
{
/* Enables clock for IOCON.: enable */
CLOCK_EnableClock(kCLOCK_Iocon);
/* Enables clock for switch matrix.: enable */
CLOCK_EnableClock(kCLOCK_Swm);

const uint32_t IOCON_INDEX_PIO0_7_config = (/* No addition pin function */
IOCON_PIO_MODE_INACT |
/* Enable hysteresis */
IOCON_PIO_HYS_EN |
/* Input not invert */
IOCON_PIO_INV_DI |
/* Disables Open-drain function */
IOCON_PIO_OD_DI |
/* Bypass input filter */
IOCON_PIO_SMODE_BYPASS |
/* IOCONCLKDIV0 */
IOCON_PIO_CLKDIV0);
/* PIO0 PIN7 (coords: 45) is configured as ADC0, CH, 0. */
IOCON_PinMuxSet(IOCON, IOCON_INDEX_PIO0_7, IOCON_INDEX_PIO0_7_config);

////////////////////////ADC_7 PIO0_19
const uint32_t IOCON_INDEX_PIO0_19_config = (/* No addition pin function */
IOCON_PIO_MODE_INACT |
/* Enable hysteresis */
IOCON_PIO_HYS_EN |
/* Input not invert */
IOCON_PIO_INV_DI |
/* Disables Open-drain function */
IOCON_PIO_OD_DI |
/* Bypass input filter */
IOCON_PIO_SMODE_BYPASS |
/* IOCONCLKDIV0 */
IOCON_PIO_CLKDIV0);
/* PIO0 PIN7 (coords: 45) is configured as ADC0, CH, 0. */
IOCON_PinMuxSet(IOCON, IOCON_INDEX_PIO0_19, IOCON_INDEX_PIO0_19_config);

//////////////////////////

const uint32_t IOCON_INDEX_PIO1_16_config = (/* Selects pull-up function */
IOCON_PIO_MODE_PULLUP |
/* Enable hysteresis */
IOCON_PIO_HYS_EN |
/* Input not invert */
IOCON_PIO_INV_DI |
/* Disables Open-drain function */
IOCON_PIO_OD_DI |
/* Bypass input filter */
IOCON_PIO_SMODE_BYPASS |
/* IOCONCLKDIV0 */
IOCON_PIO_CLKDIV0);
/* PIO1 PIN16 (coords: 36) is configured as USART0, RXD. */
IOCON_PinMuxSet(IOCON, IOCON_INDEX_PIO1_16, IOCON_INDEX_PIO1_16_config);

const uint32_t IOCON_INDEX_PIO1_17_config = (/* Selects pull-up function */
IOCON_PIO_MODE_PULLUP |
/* Enable hysteresis */
IOCON_PIO_HYS_EN |
/* Input not invert */
IOCON_PIO_INV_DI |
/* Disables Open-drain function */
IOCON_PIO_OD_DI |
/* Bypass input filter */
IOCON_PIO_SMODE_BYPASS |
/* IOCONCLKDIV0 */
IOCON_PIO_CLKDIV0);
/* PIO1 PIN17 (coords: 37) is configured as USART0, TXD. */
IOCON_PinMuxSet(IOCON, IOCON_INDEX_PIO1_17, IOCON_INDEX_PIO1_17_config);

/* USART0_TXD connect to P1_17 */
SWM_SetMovablePinSelect(SWM0, kSWM_USART0_TXD, kSWM_PortPin_P1_17);

/* USART0_RXD connect to P1_16 */
SWM_SetMovablePinSelect(SWM0, kSWM_USART0_RXD, kSWM_PortPin_P1_16);

/* ADC_CHN0 connect to P0_7 */
SWM_SetFixedPinSelect(SWM0, kSWM_ADC_CHN0, true);

//////////////////////
/* ADC_CHN0 connect to P0_7 */
SWM_SetFixedPinSelect(SWM0, kSWM_ADC_CHN7, true);
//////////////////////
/* Disable clock for switch matrix. */
CLOCK_DisableClock(kCLOCK_Swm);
}

 

In the main(), I only changed the channel

//#define DEMO_ADC_SAMPLE_CHANNEL_NUMBER 0U
#define DEMO_ADC_SAMPLE_CHANNEL_NUMBER 7U

From the

Pls have a try console, the ADC result is correct.

Hope it can help you

BR

XiangJun Rong

0 Kudos

408 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi,

I attach the project, pls have a try

Pls connect the PIO0_19 pin which is pin 16 of J2 on the LPB860-MAX board to GND or 3.3V and check the result.

BR

XiangJun Rong

0 Kudos