LPC4370 HSADC does not work correctly with clocking from PLLAUDIO.

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

LPC4370 HSADC does not work correctly with clocking from PLLAUDIO.

Jump to solution
1,943 Views
vitaliylivnov
Contributor III

We are trying to figure out how to configure the HSADC microcontroller LPC4370. We took the project periph_hsadc as a basis. When clocking ADC from MAINPLL and USBPLL everything works fine, but when using PLLAUDIO tuned to 80 MHz, the ADC reads some noise that is not related to the input signal. How can we solve this problem? Thanks.

Here is our code:

static void HsadcInit(void) {
     uint32_t freqHSADC = 0;

     /* Setting up the HSADC clock is more complex than other peripherals.
        The HSADC clock is driven directly from the CGU/CCU and has limited
        source and divider options. Because the HSADC clocking is entirely
        handled outside the HSADC peripheral, example code for setting up
        the CGU/CCU to get a rough HSADC clock rate is included in this
        example. */
     setupClock(HSADC_CLOCK_RATE);

     /* Initialize HSADC */
     Chip_HSADC_Init(LPC_ADCHS);

     /* Show the actual HSADC clock rate */
     freqHSADC = Chip_HSADC_GetBaseClockRate(LPC_ADCHS);
     DEBUGOUT_S("HSADC sampling rate = %dKHz\r\n", freqHSADC / 1000);

     /* Setup FIFO trip points for interrupt/DMA to 8 samples, no packing */
     Chip_HSADC_SetupFIFO(LPC_ADCHS, 8, false);

     /* Software trigger only, 0x90 recovery clocks, add channel IF to FIFO entry */
     Chip_HSADC_ConfigureTrigger(LPC_ADCHS, HSADC_CONFIG_TRIGGER_SW,
                                        HSADC_CONFIG_TRIGGER_RISEEXT, HSADC_CONFIG_TRIGGER_NOEXTSYNC,
                                        HSADC_CHANNEL_ID_EN_ADD, 0x90);

     /* Select both positive and negative DC biasing for input 3 */
     Chip_HSADC_SetACDCBias(LPC_ADCHS, 0, HSADC_CHANNEL_DCBIAS, HSADC_CHANNEL_NODCBIAS);
     //Chip_HSADC_SetACDCBias(LPC_ADCHS, 2, HSADC_CHANNEL_DCBIAS, HSADC_CHANNEL_DCBIAS);

     /* Set low A threshold to 10% and high A threshold to 90% */
     Chip_HSADC_SetThrLowValue(LPC_ADCHS, 0, ((HSADC_MAX_SAMPLEVAL * 1) / 10));
     Chip_HSADC_SetThrHighValue(LPC_ADCHS, 0, ((HSADC_MAX_SAMPLEVAL * 9) / 10));

     /* Set low B threshold to 40% and high B threshold to 60% */
     Chip_HSADC_SetThrLowValue(LPC_ADCHS, 1, ((HSADC_MAX_SAMPLEVAL * 4) / 10));
     Chip_HSADC_SetThrHighValue(LPC_ADCHS, 1, ((HSADC_MAX_SAMPLEVAL * 6) / 10));

     /* Setup data format for offset binary and update clock settings. This function
        should be called whenever a clock change is made to the HSADC */
     Chip_HSADC_SetPowerSpeed(LPC_ADCHS, false);

     /* Enable HSADC power */
     Chip_HSADC_EnablePower(LPC_ADCHS);

     /* Setup HSADC table 0 descriptors */
     /* Descriptor entries are mapped as follows */
     /* 0 : mapped to input 0, branch to next descriptor after sample, match time
        is 0x90 clocks for the initial sample (must be greater than or equal to
           recovery clocks for auto power-up), test against threshold A */
     Chip_HSADC_SetupDescEntry(LPC_ADCHS, 0, 0, (HSADC_DESC_CH(0) |
                                                            HSADC_DESC_BRANCH_NEXT | HSADC_DESC_MATCH(0x95) | HSADC_DESC_THRESH_A |
                                                            HSADC_DESC_RESET_TIMER));

     Chip_HSADC_SetupDescEntry(LPC_ADCHS, 0, 1, (HSADC_DESC_CH(0) |
                                                            HSADC_DESC_BRANCH_NEXT | HSADC_DESC_MATCH(0x01) | HSADC_DESC_THRESH_A |
                                                            HSADC_DESC_RESET_TIMER));
     Chip_HSADC_SetupDescEntry(LPC_ADCHS, 0, 2, (HSADC_DESC_CH(0) |
                                                            HSADC_DESC_BRANCH_NEXT | HSADC_DESC_MATCH(0x01) | HSADC_DESC_THRESH_A |
                                                            HSADC_DESC_RESET_TIMER));
     Chip_HSADC_SetupDescEntry(LPC_ADCHS, 0, 3, (HSADC_DESC_CH(0) |
                                                            HSADC_DESC_BRANCH_NEXT | HSADC_DESC_MATCH(0x01) | HSADC_DESC_THRESH_A |
                                                            HSADC_DESC_RESET_TIMER));
     Chip_HSADC_SetupDescEntry(LPC_ADCHS, 0, 4, (HSADC_DESC_CH(0) |
                                                            HSADC_DESC_BRANCH_NEXT | HSADC_DESC_MATCH(0x01) | HSADC_DESC_THRESH_A |
                                                            HSADC_DESC_RESET_TIMER));
     Chip_HSADC_SetupDescEntry(LPC_ADCHS, 0, 5, (HSADC_DESC_CH(0) |
                                                            HSADC_DESC_BRANCH_NEXT | HSADC_DESC_MATCH(0x01) | HSADC_DESC_THRESH_A |
                                                            HSADC_DESC_RESET_TIMER));
     Chip_HSADC_SetupDescEntry(LPC_ADCHS, 0, 6, (HSADC_DESC_CH(0) |
                                                            HSADC_DESC_BRANCH_NEXT | HSADC_DESC_MATCH(0x01) | HSADC_DESC_THRESH_A |
                                                            HSADC_DESC_RESET_TIMER));

     /* 1 : mapped to input 0, branch to next descriptor after sample, match time
        is 1, test against threshold A */
     //Добавил HSADC_DESC_HALT и HSADC_DESC_INT после данного дескриптора
     Chip_HSADC_SetupDescEntry(LPC_ADCHS, 0, 7, (HSADC_DESC_CH(0) | HSADC_DESC_BRANCH_NEXT
                                                            | HSADC_DESC_HALT | HSADC_DESC_INT
                                                            | HSADC_DESC_MATCH(1) | HSADC_DESC_THRESH_A | HSADC_DESC_RESET_TIMER));

     Chip_HSADC_EnableInts(LPC_ADCHS, 0, (HSADC_INT0_DSCR_DONE));

     /* Enable HSADC interrupts in NVIC */
     NVIC_EnableIRQ(ADCHS_IRQn);

     /* Update descriptor tables - needed after updating any descriptors */
     Chip_HSADC_UpdateDescTable(LPC_ADCHS, 0);

     /* Setup periodic timer to perform software triggering */
     timer_setup();
}


/* Clock setup function for generating approximate HSADC clock. Trim this
   example function as needed to get the size down in a production system. */
static void setupClock(uint32_t rate)
{
//----PLLAUDIO----//
     SetUpPLL0audio(100, 15, 1);
     Chip_Clock_SetBaseClock(CLK_BASE_ADCHS, CLKIN_AUDIOPLL, true, false); /* HSADC base clock = divider A input */

//----MAINPLL----//
//     Chip_Clock_SetDivider(CLK_IDIV_A, CLKIN_MAINPLL, 2); /* Setup divider A for main PLL rate divided by 3 */
//     Chip_Clock_SetBaseClock(CLK_BASE_ADCHS, CLKIN_IDIVA, true, false);

//----USBPLL----//
//          Chip_USB0_Init(); /* Initialize the USB0 PLL to 480 MHz */
//          Chip_Clock_SetDivider(CLK_IDIV_A, CLKIN_USBPLL, 2); /* Source DIV_A from USB0PLL, and set divider to 2 (Max div value supported is 4) [IN 480 MHz; OUT 240 MHz */
//          Chip_Clock_SetDivider(CLK_IDIV_B, CLKIN_IDIVA, 3); /* Source DIV_B from DIV_A, [IN 240 MHz; OUT 80 MHz */
//          Chip_Clock_SetBaseClock(CLK_BASE_ADCHS, CLKIN_IDIVB, true, false); /* Source ADHCS base clock from DIV_B */


     uint32_t frequency = ClockSourceFreqMeasure(CLKIN_AUDIOPLL);
     DEBUGOUT_S("Measured frequency=%d\r\n", frequency);

     /* Enable ADC clock */
     Chip_Clock_EnableOpts(CLK_ADCHS, true, true, 1);
}

/**************************************************************************//**
 *
 * @brief Setup PLL0Audio as XTAL*msel/(nsel*psel)
 *
 * @param [in] msel  Multiple value
 * @param [in] nsel  Pre-divider value
 * @param [in] psel  Post-divider value
 *
 * @return  void
 *
 *****************************************************************************/
void SetUpPLL0audio(uint32_t msel, uint32_t nsel, uint32_t psel)
{

  /* disable clock, disable skew enable, power down pll,
  * (dis/en)able post divider, (dis/en)able pre-divider,
  * disable free running mode, disable bandsel,
  * enable up limmiter, disable bypass
  */
  LPC_CGU->PLL[CGU_AUDIO_PLL].PLL_CTRL = (6 << 24)   /* source = XTAL OSC 12 MHz */
                            | _BIT(0);  /* power down */

  /* set NDEC, PDEC and MDEC register */
  LPC_CGU->PLL[CGU_AUDIO_PLL].PLL_NP_DIV = (NDEC_Encode(nsel) << 12) | PDEC_Encode(psel);
  LPC_CGU->PLL[CGU_AUDIO_PLL].PLL_MDIV = MDEC_Encode(msel);

  LPC_CGU->PLL[CGU_AUDIO_PLL].PLL_CTRL = (6 << 24)   /* source = XTAL OSC 12 MHz */
                                      | (6<< 12);     // fractional divider off and bypassed

  /* wait for lock */
  while (!(LPC_CGU->PLL[CGU_AUDIO_PLL].PLL_STAT & 1));

  /* enable clock output */
  LPC_CGU->PLL[CGU_AUDIO_PLL].PLL_CTRL |= (1<<4); /* CLKEN */
}
Labels (1)
1 Solution
1,623 Views
vitaliylivnov
Contributor III

Hi, jeremyzhou‌. 

Thank you for trying to help. We figured out that the cause of the problem is the incorrect HSADC power configuration in the Chip_HSADC_SetPowerSpeed function. And the reason for the incorrect configuration is that we did not set the value of the current AUDIOPLL frequency to the audio_usb_pll_freq array. Therefore, after setting the next value, the problem has been fixed:

audio_usb_pll_freq [CGU_AUDIO_PLL] = 80000000;

View solution in original post

0 Kudos
9 Replies
1,623 Views
jeremyzhou
NXP Employee
NXP Employee

Hi Vitaliy Livnov ,

Thank you for your interest in NXP Semiconductor products and for the opportunity to serve you.
I was wondering if you can illustrate what the behavior of noise which disturbs the HSADC, in further, I'll appreciate if you can upload a compile-able demo code.

pastedImage_1.png
And after checking, I find the USBPLL is not the clock source of the HSADC, so it doesn't make sense for the HSADC works well when clock source is the USBPLL, please check it again.
Have a great day,
TIC

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos
1,623 Views
vitaliylivnov
Contributor III

Hello, jeremyzhou. Thanks for your reply. Here is our demo code. We created it in MCUXpresso IDE v10.0.2. You can use USE_PLLAUDIO, USE_MAINPLL and USE_USBPLL defines in scopeFunctional.c to switch HSADC clock source.

We also attach sample graphics at sample rate = 1000 Hz, samples number = 500. ADC input was not connected anywhere.

2019-01-08 (1).png

MAINPLL source.

2019-01-08 (2).png

AUDIOPLL source.

0 Kudos
1,623 Views
jeremyzhou
NXP Employee
NXP Employee

Hi Vitaliy Livnov ,

Thanks for your reply.
After reviewing the code, I think the 'phenomenon' is raised by incorrect PLL0_AUDIO configuration.
So I'd like to suggest to follow these below produces to validating the PLL0_AUDIO configuration.
1. Assure fit these features.
2. Output the Fout of PLL0_AUDIO via the CLKOUT pin, and illustrates the output in the oscilloscope.
Have a great day,
TIC

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos
1,623 Views
vitaliylivnov
Contributor III

Hi, jeremyzhou. We output the signal from AUDIOPLL to the CLKOUT pin and make sure that the oscilloscope displays a stable signal with a frequency of 80 MHz. On other clock sources, we received the same signal.
We also noticed that by decreasing the frequency of AUDIOPLL to 40 MHz and lower the work of the ADC is stabilized.

We know that AUDIOPLL can be used for clocking HSADC at frequencies up to 80 MHz, since this approach is used in the LabTool project.

0 Kudos
1,623 Views
jeremyzhou
NXP Employee
NXP Employee

Hi Vitaliy Livnov,

After reviewing the code, I find the SetUpPLL0audio(100, 15, 1); is not good, even it can achieve the Fout =  Fcco=FINxM/(NxP)= 12x100/(15x1)= 80 MHz.
However, the Fcco=160 MHz, it doesn't fit this requirement: CCO frequency: 275 MHz to 550 MHz.
So I'd like to suggest you can use these paramaters instead the original ones.
SetUpPLL0audio(20, 1, 3); // Fcco = 480 MHz
Please give a try.
Have a great day,
TIC

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos
1,623 Views
vitaliylivnov
Contributor III

Hi, jeremyzhou. We have already tried these values with the same result.

0 Kudos
1,623 Views
jeremyzhou
NXP Employee
NXP Employee

Hi Vitaliy Livnov,

Thanks for your reply.

I'm working on it now, and I'll inform ASAP when I work it out.
Have a great day,
TIC

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

1,624 Views
vitaliylivnov
Contributor III

Hi, jeremyzhou‌. 

Thank you for trying to help. We figured out that the cause of the problem is the incorrect HSADC power configuration in the Chip_HSADC_SetPowerSpeed function. And the reason for the incorrect configuration is that we did not set the value of the current AUDIOPLL frequency to the audio_usb_pll_freq array. Therefore, after setting the next value, the problem has been fixed:

audio_usb_pll_freq [CGU_AUDIO_PLL] = 80000000;
0 Kudos
1,623 Views
jeremyzhou
NXP Employee
NXP Employee

Hi Vitaliy Livnov,

Yes,it seems a bit weird that the HSADC sampling rate is 0 KHz.
I'm glad to hear that your issue is solved.
Have a great day,
TIC

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos