ADC conversion does not complete

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

ADC conversion does not complete

Jump to solution
2,359 Views
gschelotto
Contributor V

Hello,

I've configured 5 ADC0 channels (ADC interrupt disabled) on KE02Z+KDS v3.0 as shown:

Untitled.png

and defined 2 groups (1st of channel 0 and 2nd of channel 1 to 4)

Untitled2.png

The goal is to get 1 ADC channel sample every 1ms (timer0 triggered) and 4 ADC channel samples every 10ms (timer1 triggered). Here's the initialization code:

LDD_ADC_TSample samplegroup[AD1_CHANNEL_COUNT] = {AD1_ADC0_SE2, AD1_ADC0_SE0, AD1_ADC0_SE1, AD1_ADC0_SE3, AD1_ADC0_SE6};

word acqValueGroup0[AD1_STATIC_GROUP_0_SAMPLE_COUNT];

word acqValueGroup1[AD1_STATIC_GROUP_1_SAMPLE_COUNT];

AD1_CreateSampleGroup(AD1_DeviceData, samplegroup, AD1_CHANNEL_COUNT);

for the first ADC channel (Timer0 ISR):

AD1_SelectSampleGroup(AD1_DeviceData, 0U);

AD1_StartSingleMeasurement(AD1_DeviceData);

while (!AD1_GetMeasurementCompleteStatus(AD1_DeviceData)) {}; // Wait for conversion completeness

AD1_GetMeasuredValues(AD1_DeviceData, acqValueGroup0);

and for the left 4 channels (Timer1 ISR):

AD1_SelectSampleGroup(AD1_DeviceData, 1U);

AD1_StartSingleMeasurement(AD1_DeviceData);

while (!AD1_GetMeasurementCompleteStatus(AD1_DeviceData));     // Wait for conversion completeness

AD1_GetMeasuredValues(AD1_DeviceData, acqValueGroup1);

The problem is the execution stuck in the while loop (conversion never ends). What I am missing?

regards,

gaston

0 Kudos
Reply
1 Solution
1,567 Views
marek_neuzil
NXP Employee
NXP Employee

Hello Gaston,

I have analyzed you application and I have found out following issues:

- The hard fault exception (CPU_Interrupt subroutine) is caused by unitialized pointer in your application. You are using AD1_DeviceDataPtr pointer that is initialized in the appInit() function but the TU1 component is intialized in the PE_low_level_init (timer is enabled). The TU1_OnCounterRestart is invoked before the AD1_DeviceDataPtr is initialized (null pointer exception). Therefore you must disable the timer in the initialization (set the Enabled in Init. Code property to no) and call TU1_Enable() method after the AD1_DeviceDataPtr pointer is initialized in the acqInit() function.

- The AD1 component (driver) initialization is executed twice in your application. There is enabled autoinitialization in the AD1 component (the Autoinitialization property is set to yes; the AD1_Init() is called in the PE_low_level_init()) and you also call AD1_Init() function in the acqInit() function. If you want to use the AD1_DeviceDataPtr you can just do assignment AD1_DeviceDataPtr =  AD1_DeviceData; (AD1_DeviceData is macro defined in the AD1.h and it provides initialized pointer to device data).

See for example you code in the Event.c:

void TU1_OnCounterRestart(LDD_TUserData *UserDataPtr)

{

  /* Write your code here ... */

word i;

LDD_TError Error;

    . . .

    Error = AD1_SelectSampleGroup(AD1_DeviceDataPtr, 0U);

    Error = AD1_StartSingleMeasurement(AD1_DeviceDataPtr);

    while ((ADC_PDD_GetConversionCompleteFlag(ADC_BASE_PTR, NULL)) == FALSE);

    AD1_Main(AD1_DeviceDataPtr);

    while (!AD1_GetMeasurementCompleteStatus(AD1_DeviceDataPtr));     // Wait for conversion completeness

    AD1_GetMeasuredValues(AD1_DeviceData, acqValueGroup0);

    acqValueGroup0[0] -= 2047;

   . . .

I.e. you use AD1_DeviceDataPtr pointer and AD1_DeviceData macro in one function (the same pointers).

I have fixed your application, see the attached archive. I have also checked the you can measure any sample group in the TU1_OnCounterRestart() event, i.e. you can call

Error = AD1_SelectSampleGroup(AD1_DeviceDataPtr, 0U);

or

Error = AD1_SelectSampleGroup(AD1_DeviceDataPtr, 1U);

Both sample groups can be measured in this event.

I see also another synchronization issue in your application. There are measurement executed in an interrupt (TU1_OnCounterRestart() event) and in the main process - acqProcess() function. I am not sure but it seems to me that these measurement are not synchronized. i.e. you must ensure that acqProcess() function (measurement of the AD1 channels) is not interrupt by TU1 interrupt (TU1_OnCounterRestart() event call). Otherwise AD1 results can corrupted.

Best Regards,

Marek Neuzil

View solution in original post

0 Kudos
Reply
11 Replies
1,567 Views
marek_neuzil
NXP Employee
NXP Employee

Hello Gaston,

It seems that your problem is in the source code of Timers' interrupt service routines. I suppose that you are using the ADC component with interrupt enabled. The ADC driver uses also interrupt service routines. When you wait in a timer interrupt service routine for finishing the ADC conversions the ADC driver is blocked (interrupt service routine is not invoked) in your application.

I would recommend to start the ADC conversion (AD1_StartSingleMeasurement() function call) in the timer ISRs only and then you can use the ADC event OnMeasurementComplete to finishing subsequent actions (AD1_GetMeasuredValues() and so on).

Best Regards,

Marek Neuzil

0 Kudos
Reply
1,567 Views
gschelotto
Contributor V

Hello Marek/Alice,

I suppose that you are using the ADC component with interrupt enabled

The ADC interrupt is disabled in PE. I've digged into ADC component help and I've found some hints from the typical usage without interrupt service

Untitled.png

Then I rewrite my code as shown (for the 4-sample group 1)

Init code

// Create 4-sample group

acqSampleGroup1[0].ChannelIdx = 1U;

acqSampleGroup1[1].ChannelIdx = 2U;

acqSampleGroup1[2].ChannelIdx = 3U;

acqSampleGroup1[3].ChannelIdx = 4U;

while loop

Error = AD1_CreateSampleGroup(AD1_DeviceDataPtr, (LDD_ADC_TSample *)acqSampleGroup1, AD1_STATIC_GROUP_1_SAMPLE_COUNT);  // Set created sample group

Error = AD1_SelectSampleGroup(AD1_DeviceDataPtr, 1U);

Error = AD1_StartSingleMeasurement(AD1_DeviceDataPtr);

while (!AD1_GetMeasurementCompleteStatus(AD1_DeviceDataPtr));     // Wait for conversion completeness

Error = AD1_GetMeasuredValues(AD1_DeviceDataPtr, acqValueGroup1);

However the problem persist and the execution stucks in AD1_GetMeasurementCompleteStatus(AD1_DeviceDataPtr). How can I go further?

Untitled2.png

regards,

gaston

0 Kudos
Reply
1,567 Views
Jorge_Gonzalez
NXP Employee
NXP Employee

Hello Gaston:

In polling mode (no interrupts) try changing your code like this:

  1. Error = AD1_CreateSampleGroup(AD1_DeviceDataPtr, (LDD_ADC_TSample *)acqSampleGroup1, AD1_STATIC_GROUP_1_SAMPLE_COUNT);  // Set created sample group 
  2. Error = AD1_SelectSampleGroup(AD1_DeviceDataPtr, 1U);
  3. Error = AD1_StartSingleMeasurement(AD1_DeviceDataPtr);
  4. while((ADC_PDD_GetConversionCompleteFlag(ADC_BASE_PTR, NULL)) == FALSE);
  5. AD1_Main(AD1_DeviceDataPtr);
  6. while (!AD1_GetMeasurementCompleteStatus(AD1_DeviceDataPtr));    // Wait for conversion completeness  
  7. Error = AD1_GetMeasuredValues(AD1_DeviceDataPtr, acqValueGroup1);

Let me know if that works.

Regards!

Jorge Gonzalez

0 Kudos
Reply
1,567 Views
gschelotto
Contributor V

Jorge, it works as expected. Now I get the a correct measurement value for the 4-channel (group 1).

However when I try to get 1-channel (group 0) in Timer1 isr the execution halts this way:

Untitled.png

I stepped into AD1_CreateSampleGroup function until the halt occurs and get this information:

Untitled2.png

regards,

gaston

0 Kudos
Reply
1,567 Views
gschelotto
Contributor V

Any feedback please? I need to perform the 1-channel (group 0) acquisition in Timer1 ISR.

0 Kudos
Reply
1,567 Views
marek_neuzil
NXP Employee
NXP Employee

Hello Gaston,

Could you provide your application for the analysis, please? There can be several reasons of the issue (stack overflow, defect in a driver and so on).

The ADC_LDD driver contains a bug - when the event OnMeasurementComplete is enabled, interrupts are disabled, the driver code of the ADC_LDD enables interrupts in ADC device registers. It cause the invocation of the CPU_Interrupt() routine. Please, disable OnMeasurementComplete event in the ADC_LDD component when you use the driver in polling mode (interrupts are disabled).

Best Regards,

Marek Neuzil

0 Kudos
Reply
1,567 Views
gschelotto
Contributor V

Marek,

Sorry for the delay in replying. I attach the application for the analysis. Relevant code is in Events.c (line 148) and app.c (line 75). I've disabled the OnMeasurementComplete event in the ADC_LDD component but it does not solve the issue.

regards,

gaston

0 Kudos
Reply
1,568 Views
marek_neuzil
NXP Employee
NXP Employee

Hello Gaston,

I have analyzed you application and I have found out following issues:

- The hard fault exception (CPU_Interrupt subroutine) is caused by unitialized pointer in your application. You are using AD1_DeviceDataPtr pointer that is initialized in the appInit() function but the TU1 component is intialized in the PE_low_level_init (timer is enabled). The TU1_OnCounterRestart is invoked before the AD1_DeviceDataPtr is initialized (null pointer exception). Therefore you must disable the timer in the initialization (set the Enabled in Init. Code property to no) and call TU1_Enable() method after the AD1_DeviceDataPtr pointer is initialized in the acqInit() function.

- The AD1 component (driver) initialization is executed twice in your application. There is enabled autoinitialization in the AD1 component (the Autoinitialization property is set to yes; the AD1_Init() is called in the PE_low_level_init()) and you also call AD1_Init() function in the acqInit() function. If you want to use the AD1_DeviceDataPtr you can just do assignment AD1_DeviceDataPtr =  AD1_DeviceData; (AD1_DeviceData is macro defined in the AD1.h and it provides initialized pointer to device data).

See for example you code in the Event.c:

void TU1_OnCounterRestart(LDD_TUserData *UserDataPtr)

{

  /* Write your code here ... */

word i;

LDD_TError Error;

    . . .

    Error = AD1_SelectSampleGroup(AD1_DeviceDataPtr, 0U);

    Error = AD1_StartSingleMeasurement(AD1_DeviceDataPtr);

    while ((ADC_PDD_GetConversionCompleteFlag(ADC_BASE_PTR, NULL)) == FALSE);

    AD1_Main(AD1_DeviceDataPtr);

    while (!AD1_GetMeasurementCompleteStatus(AD1_DeviceDataPtr));     // Wait for conversion completeness

    AD1_GetMeasuredValues(AD1_DeviceData, acqValueGroup0);

    acqValueGroup0[0] -= 2047;

   . . .

I.e. you use AD1_DeviceDataPtr pointer and AD1_DeviceData macro in one function (the same pointers).

I have fixed your application, see the attached archive. I have also checked the you can measure any sample group in the TU1_OnCounterRestart() event, i.e. you can call

Error = AD1_SelectSampleGroup(AD1_DeviceDataPtr, 0U);

or

Error = AD1_SelectSampleGroup(AD1_DeviceDataPtr, 1U);

Both sample groups can be measured in this event.

I see also another synchronization issue in your application. There are measurement executed in an interrupt (TU1_OnCounterRestart() event) and in the main process - acqProcess() function. I am not sure but it seems to me that these measurement are not synchronized. i.e. you must ensure that acqProcess() function (measurement of the AD1 channels) is not interrupt by TU1 interrupt (TU1_OnCounterRestart() event call). Otherwise AD1 results can corrupted.

Best Regards,

Marek Neuzil

0 Kudos
Reply
1,567 Views
gschelotto
Contributor V

Marek, I'm very grateful for your help. You have not only fixed the issue but you've also found potential bugs in my code.

best regards,

gaston

0 Kudos
Reply
1,567 Views
gschelotto
Contributor V

One more thing. I've moved 1-channel (group 0) methods from TU1 ISR to the main loop and it works fine (code execution does not halt). Why it does not work when ADC methods are placed in TU1 ISR (every 312us)? I've measured the acquisition time and it takes less than 80us.

regards,

gaston

0 Kudos
Reply
1,567 Views
Alice_Yang
NXP TechSupport
NXP TechSupport

Hello gaston,

Please step over to the function "AD1_GetMeasurementCompleteStatus(AD1_DeviceData)" to check stop on which code ?

And i recommend you refer to theTypical Usage of help on component to configure your code :

pastedImage_0.png

Hope it helps

Alice

0 Kudos
Reply