ADC_ETC results using FreeRTOS semaphore vs while loop?

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

ADC_ETC results using FreeRTOS semaphore vs while loop?

1,299 Views
jackking
Senior Contributor I

I have been stumped by this issue for a bit.

When initiating a reading from both ADC_ETC converters, I have tried two different methods of waiting for the results:
1. Wait in a while() loop for two flags to be set by the two conversion complete IRQs.  This seems to work well, with very little fluctuation of the readings.  The downside is that the while() loop is just spinning while waiting for the conversions to complete.

2. Block the task on a FreeRTOS semaphore that is given when both conversion complete IRQs have fired.  This lets the CPU idle while the conversions are performed.  Using this method, I see occasional fluctuations in the ADC readings which lead to incorrect behaviour.

Does someone have any ideas or tips on why using semaphores may impact the ADC conversions?  Power fluctuations due to task switching?

0 Kudos
7 Replies

1,288 Views
jeremyzhou
NXP Employee
NXP Employee

Hi,
Thank you for your interest in NXP Semiconductor products and for the opportunity to serve you.
1) Does someone have any ideas or tips on why using semaphores may impact the ADC conversions? Power fluctuations due to task switching?
-- In my opinion, the phenomenon is may be related to software architecture, so I was wondering if you can share the codes of the above two designs.
Have a great day,
TIC

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

 

- We are following threads for 7 weeks after the last post, later replies are ignored
Please open a new thread and refer to the closed one, if you have a related question at a later point in time.
-------------------------------------------------------------------------------

0 Kudos

1,283 Views
jackking
Senior Contributor I

OK, I have spent the last few days troubleshooting this.   I have narrowed it down to a weird GPIO issue.

I am using GPIO to set a mux address before each conversion.   Every once in awhile the GPIO pin values are not correctly set to the current address when the ADC conversion runs, instead the GPIO are still set to the previous address, which causes the ADC reading to be for the wrong input.

So, this isn't an ADC reading issue. I don't know why the GPIO settings are not correct.  I even put a check in after setting the GPIO address, to see that the pins are correct immediately after setting them.
 
Checking the GPIO pin values again when the ADC interrupt has been triggered, they are incorrect (and different than the values read immediately after setting them).



0 Kudos

1,278 Views
jeremyzhou
NXP Employee
NXP Employee

Hi,
Thanks for your reply.
it seems a bit weird, I was wondering if you can introduce the testing environment, such as code, board, etc.
Plus, whether you can upload the code which can replicate the above phenomenon.
Have a great day,
TIC

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

 

- We are following threads for 7 weeks after the last post, later replies are ignored
Please open a new thread and refer to the closed one, if you have a related question at a later point in time.
-------------------------------------------------------------------------------

0 Kudos

1,266 Views
jackking
Senior Contributor I

I will need to see if it makes sense to create a dedicated test project that I can share, and if it would have the same behaviour.  I am using a custom board design, with a full project, which I can't really share.

Since this seems to happen only when using FreeRTOS vs. a while() loop, I assume something about a context switch is causing the GPIO change for the address to be blocked or overwritten with a previous value.

I ran a debug (in SEGGER SystemView) and the GPIO issue only happened infrequently (every ~100k executions).

Here is a code snippet extract that shows what I use to set and check the GPIO for the address.  This is modified code from my project, so don't try to compile it.

 

#define IO_MUX_GPIO GPIO1
#define IO_MUX_0_PIN 28U
#define IO_MUX_1_PIN 29U
#define IO_MUX_2_PIN 30U

volatile uint8_t g_addrNum = 0U;
volatile uint16_t g_AdcConversionValue2;

void ADC_ETC_IRQ1_IRQHandler(void)
{
	portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;

	ADC_ETC_ClearInterruptStatusFlags(ADC_ETC, kADC_ETC_Trg4TriggerSource, kADC_ETC_Done1StatusFlagMask);
	g_AdcConversionValue2 = ADC_ETC_GetADCConversionValue(ADC_ETC, 4U, 0U); 

    if (g_addrNum == (GPIO_PinRead(IO_MUX_GPIO, IO_MUX_0_PIN) | (GPIO_PinRead(IO_MUX_GPIO, IO_MUX_1_PIN) << 1) | (GPIO_PinRead(IO_MUX_GPIO, IO_MUX_2_PIN) << 2)))
	{
	    GPIO_PortClear(IO_MUX_GPIO, 0x70000000);
	    if (g_addrNum != 5)
	    {
            g_addrNum++;
		    GPIO_PortSet(IO_MUX_GPIO, g_addrNum << 28);
	    }
        else
        {
            g_addrNum = 0;
        }
		// give the semaphore
        xSemaphoreGiveFromISR(adc_conv_sem, &xHigherPriorityTaskWoken );
	}
	else
	{
        // DANGER
        // the address doesn't match what we set it to!
	}

	if (xHigherPriorityTaskWoken != pdFALSE)
	{
		portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
	}
	__DSB();
}

 




0 Kudos

1,259 Views
jeremyzhou
NXP Employee
NXP Employee

Hi,
Thanks for your reply.
You can try to use the below function to provide a basic critical section implementation to handle GPIO.

taskENTER_CRITICAL() or taskENTER_CRITICAL_FROM_ISR()


taskEXIT_CRITICAL() or taskEXIT_CRITICAL_FROM_ISR()

Have a great day,
TIC

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

 

- We are following threads for 7 weeks after the last post, later replies are ignored
Please open a new thread and refer to the closed one, if you have a related question at a later point in time.
-------------------------------------------------------------------------------

 

0 Kudos

1,220 Views
jackking
Senior Contributor I

I'm not sure if this is helpful, but I have captured the error condition on a debug trace in SystemView and annotated it:
GPIO_ERROR_DEBUG.png

0 Kudos

1,252 Views
jackking
Senior Contributor I

Thanks, I had already tried a critical section, and the behaviour was the same.

I think I have narrowed it down somewhat.

The GPIO mux address lines are wrong/reset when the ADC interrupt is fired and preempts another FreeRTOS task that is updating a display.

The display task is using the fsl_flexio_mculcd driver which is configured for FlexIO parallel output.  The display CS, RS and FlexIO use the same GPIO base (GPIO1) as the mux address lines, although the individual pins don't overlap.

It seems that either the CS, RS or FlexIO setting in the display update routines must occasionally reset the mux address lines when the task switches context from the ADC interrupt.

I'm not sure where to go from there, as the fsl_flexio_mculcd driver is library code from NXP.



0 Kudos