ADC interrupt is missed in FreeRTOS on Zynq microZED board

fanksting wrote on Wednesday, June 15, 2016:


I found an issue that ADC interrupt is missed in FreeRTOS on Zynq microZED board. ADC interrupt is configured to occur in every 8ms, and during compress test, I found sometime, ADC ISR is called in 15.99ms, that is, two interrupt period( no other interrupt period number is found in test) where one interrupt occurrence is stolen.

At beginning, I suspected taskENTER_CRITICAL() and taskEXIT_CRITICAL() cause ADC interrupt miss, because it will globally disable those interrupts whose priority is below configMAX_API_CALL_INTERRUPT_PRIORITY. But, it is not the case in my code, that define:

ADC_interrupt_priority = 16

So, ADC interrupt shall not be disabled when entering critical section. One thing that I am not confortable is that I call xQueueSendFromISR() in ADC interupt ISR which shall not be called according to documents, but I don’t have any other choise if I want to notify application that ADC samples is readly.

Could you give me some suggestions about the issue? ADC interrupt miss is a disaster to the application. Thank you.

Best regards!

richard_damon wrote on Thursday, June 16, 2016:

If the priority is over the configMAX_API_CALL_INTERRUPT_PRIORITY then you can’t call the API, the basic reason is that the disabling is NEEDED to protect certain short operatons that need to be ‘atomic’.

One question is do you have any long critical sections? Critical sections should be short, just long enough to do the needed low level manipulations. Long critical sections can cause that sort of problem.

One option that can be done is to make the ADC interrupt above the API level, and have it store the data in a small circular buffer, and then kick off another interrupt that is below the API level that actually sends the data. That way the collection is never interfeared with, but the data can still be sent to a task.

fanksting wrote on Thursday, June 16, 2016:

Many hanks, I did not add critical section in application code by taskENTER_CRITICAL() and taskEXIT_CRITICAL(). The workaround does not work very well in our application which also want to monitor ADC samples in real time with fixed delay (one interrupt period). The random delay is not acceptable, so, could I replace all taskENTER_CRITICAL() and taskEXIT_CRITICAL() with vTaskSuspendAll() and xTaskResumeAll()? According to document, the latter two interfaces shall not disable interrupt globally. Is it right?

richard_damon wrote on Friday, June 17, 2016:

Yes, the vTaskSuspendAll()/vTaskResumeAll() is the API to use if you need to make a longish critical section that doesn’t need/want to block interrupts. If this is the problem, they your current critical section is too long. taskENTER_CRITICAL()/taskEXIT_CRITICAL() should only be used very short (and generally deterministic) periods.

fanksting wrote on Friday, June 17, 2016:

Could you tell more about the difference between “vTaskSuspendAll()/vTaskResumeAll()” and “taskENTER_CRITICAL()/taskEXIT_CRITICAL()”? for example, any performance difference, or where we MUST use “taskENTER_CRITICAL()/taskEXIT_CRITICAL()” and where we MUST use “vTaskSuspendAll()/vTaskResumeAll()”. I am a little confused about the selection. Thanks.

richard_damon wrote on Friday, June 17, 2016:

THe Suspend/Resume pair provides ‘atomic’ access by stopping the changing of task, so the block is atomic with respect to task access but not for interrupt access.

The CRITICALs work by disabling the interrupts, so nothing can happen to cause a task swap, so you are atomic to tasks and interrupt routines. The problem with CRITICALs is that they block ALL interrupts (at or below the API level), so if not kept real short can cause issues. They are needed if you need protection from access via multiple ISRS (if you need to protect against only 1 interrupt, specifically masking that might make sense).

Critical sections are faster, as they typically can be implemented with just a few instructions, so very short sections might want to use it even if you could use a Suspend/Resume section.

Your question make me wonder a bit if you understand why you want/need exclusion, and if perhaps some of what you are using these for would be better served with a mutex.

fanksting wrote on Friday, June 17, 2016:

It does make sense. Thank you!