Kwikstik audioscope demo question

cancel
Showing results for 
Search instead for 
Did you mean: 

Kwikstik audioscope demo question

Jump to solution
664 Views
cesarrabak
Contributor III

I'm studying the Kinetis KwikStik board (K40) and specially the audioscope demo.

After an analysis of the producer consumer role of PE_ISR(DMA_ADC_DoneInterrupt) (in Events.c) and ShowData() (in ProcessorExpert.c), I think the implementation in this demo has a race condition where the display function reads the data pointed to be written by the ADC thus turning useless the intended double buffer mechanism:

This is the code for the interrupt service routine:

PE_ISR(DMA_ADC_DoneInterrupt)

{

  /* Write your interrupt code here ... */

  // Clear all DMA interrupt flags

  DMA_CINT = 0x40;

  // switch bufstart to other part of buffer

  BufStart = ADC_BUFFER_SIZE - BufStart;

  // reset destination address

  DMA_TCD0_DADDR = (uint32_t)&(MeasuredValues[BufStart]);

  // toggle pin

  GPIO1_ToggleFieldBits(GPIOPtr, TST,1);

  // toggle flag

  Measured = TRUE;

}

In the routine above the setting of BufStart switches the start of the buffer to be written by the ADC and toggles the flag "Measured" to true which is tested in the main of ProcessorExpert.c:

The pertaining snippet of the code is the following:

      if (Measured) {

          cntr++;

          // display only time after time

          if (cntr > 10) {

              // display data

              ShowData();             

              cntr = 0;

          }

          // reset flag

          Measured = FALSE;

      }

The call to ShowData() is only made if the flag "Measured" is true, this procedure has the following code:

for (i=0; i<37; i++) {   

    val = MeasuredValues[BufStart+i];

    sum += val;

    // substract last average

    val = val - LastAvg;

    if (val < -150) {

       pos = 0;   

    } else if (val < -90) {

       pos = 1;   

    } else if (val < -60) {

       pos = 2;   

    } else if (val < -30) {

       pos = 3;   

    } else if (val < 30) {

       pos = 4;   

    } else if (val < 60) {

       pos = 5;   

    } else if (val < 90) {

       pos = 6;   

    } else {

       pos = 7;   

    }

So when this code is reached the for loop has the values addressed by MeasuredValues[BufStart+i] where BufStart already has been advanced to the (double) buffer region shared between the ADC DMA channel and this routine effectively reading the region which the ADC is writing to it.

Did I miss something or you agree with my understating?

Regards,

--

Cesar Rabak

0 Kudos
1 Solution
373 Views
Hui_Ma
NXP TechSupport
NXP TechSupport

Hi Cesar Rabak,

Customer could check the double buffer definition at <ProcessorExpert.c> below:

// double buffer for values. One half will be filled and the other ready to be displayed 

uint16_t MeasuredValues[2*ADC_BUFFER_SIZE];

I think your comments is correct.

For the BufStart value changed at eDMA major loop done interrupt ISR and the new Bufstart is point to the region ADC conversion value will write to.

When, it called ShowData() value is using the same region with ADC value will write to.

The fixed way is to set a new variable to get current available data region start:

volatile uint16_t DataStart;

And in ShowData() function, it need use DataStart instead of BufStart.

  DataStart = ADC_BUFFER_SIZE - BufStart;

  for (i=0; i<37; i++) {   

    val = MeasuredValues[DataStart+i];

    sum += val;

        ...

  }   


Wish it helps.
best regards
Ma Hui

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

View solution in original post

0 Kudos
6 Replies
373 Views
cesarrabak
Contributor III

HUi_Ma,

Just for the sake of completeness, I think the solution to the race problem is:

Have the variable at file ("global") scope in ProcessoExpert.c:

uint16_t DataStart; // As this variable will be used only in the main loop not longer shared with the interrupt service routine

The use of the variable with this scope will have it initialized to zero at the start of the program.

And in ShowData() function, it need use DataStart instead of BufStart.

The DataStart variable should be updated near the updating of the flag Measured in the infinite loop (in main() of ProcessorExpert.c)

  DataStart = ADC_BUFFER_SIZE - DataStart; // if we had BufStart instead will keep the race condition!!

Regards,

--

Cesar Rabak

0 Kudos
373 Views
Hui_Ma
NXP TechSupport
NXP TechSupport

Hi Cesar Rabak,

The uint16_t DataStart; variable definition scope within <ProcessorExpert.c> file.

Customer can define DataStart initialization value to 0, and there also ok to interval display ADC conversion data at MeasuredValues[] region with below code:

DataStart = ADC_BUFFER_SIZE - DataStart; // if we had BufStart instead will keep the race condition!!

Yes, I will notify the author to update related code.

Thank you for the direction.


Wish it helps.
best regards
Ma Hui

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

0 Kudos
373 Views
Hui_Ma
NXP TechSupport
NXP TechSupport

Hi Cesar,

Could you guide me where to download that Kwikstik audioscope demo?

Then I will check the whole project source and provide the feedback.


Wish it helps.
best regards
Ma Hui

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

0 Kudos
373 Views
cesarrabak
Contributor III

Hi Hui_Ma,

Thanks for the interest in my question.

The sources for this project can be downloaded from http://cache.freescale.com/files/32bit/doc/app_note/AN4688SW.ZIP. You may also be interested in the Application Note that describes this SW http://cache.freescale.com/files/32bit/doc/app_note/AN4688.pdf.

Regards,

--

Cesar Rabak

0 Kudos
374 Views
Hui_Ma
NXP TechSupport
NXP TechSupport

Hi Cesar Rabak,

Customer could check the double buffer definition at <ProcessorExpert.c> below:

// double buffer for values. One half will be filled and the other ready to be displayed 

uint16_t MeasuredValues[2*ADC_BUFFER_SIZE];

I think your comments is correct.

For the BufStart value changed at eDMA major loop done interrupt ISR and the new Bufstart is point to the region ADC conversion value will write to.

When, it called ShowData() value is using the same region with ADC value will write to.

The fixed way is to set a new variable to get current available data region start:

volatile uint16_t DataStart;

And in ShowData() function, it need use DataStart instead of BufStart.

  DataStart = ADC_BUFFER_SIZE - BufStart;

  for (i=0; i<37; i++) {   

    val = MeasuredValues[DataStart+i];

    sum += val;

        ...

  }   


Wish it helps.
best regards
Ma Hui

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

0 Kudos
373 Views
cesarrabak
Contributor III

Hi Hui_Ma,

Thank you for your time and effort in analyzing this issue.

My understanding also points to a solution on the line of yours.

I think then it remains to find a means to reach the responsible(s) for this example in Freescale to have it corrected in the download area.

Again, thanks and best regards,

--

Cesar Rabak

0 Kudos