This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Process ADC data, moved by DMA, using CMSIS DSP: what's the right way?

Hi to you all,
I've a firmware running on a NXP LPCLink2 (LPC4370: 204 Mhz Cortex M4 MCU) board which basically does this:

  • Fills the ADC FIFO @40msps.
  • Copies the data into memory using the built-in DMA Controller and 2 linked buffers.
  • Processes one buffer while the other is being filled.

My problem is that my code is too slow, and every now and then and overwrite occurs.

Using the DMA I'm saving the ADC data, which I get in Twos complement format (Offset binary is also available), in a uint32_t buffer and try to prepare them for the CMSIS DSP function by converting the buffer into float32_t: here's where the overwrite occurs. It's worth saying that I'm currently using Floating point Software, not hardware.


The CMSIS library also accepts fractional formats like q31_t, q15_t and so on, and since I don't strictly need floating point maths I could even use these formats if that could save me precious time.
It feels like I'm missing something important about this step, that's no surprise since this is my first project on a complex MCU, any help/hint/advise would be highly appreciated and would help me in my thesis.

I'll leave here the link for the (more datailed) question I asked in the NXP forums, just in case: LPC4370: ADCHS, GPDMA and CMSIS DSP | NXP Community .

Thanks in advance!

Parents
  • An AND operation will cost 1 clock cycle at least.

    I will expect that it will stay at one clock cycle because the compiler should prepare the AND-mask before the loop starts.

    The ADC, however, should always give you the same bit-values in the upper bits.

    As far as I recall, the LPC4xxx can be configured to shift the bits to the top, which means you should be able to min/max those as most-significant instead of least-significant.

    Thus you would not need to do any shifting or ANDing.

    If the LPC4xxx always insert zeros at the bottom, when in this mode, this might be the most beneficial setting you can get (because the ADC value would be ready for use as a fractional value).

    Even if the lower bits are 'rubbish', you can always clear those bits after the min/max loop, so it won't really cause any slow-down.

    -I decided to investigate things, and in UM10503, section 46.6.2 and section 46.6.4, for GDR and DRx, it says:

    BitDescription
    5:0Reserved. These bits always read as zeroes.
    15:6

    When DONE is 1, this field contains a binary fraction representing

    the voltage on the ADCn pin selected by the SEL field, divided by

    the reference voltage on the VDDA pin. Zero in the field indicates

    that the voltage on the ADCn input pin was less than, equal to, or

    close to that on VSSA, while 0x3FF indicates that the voltage on

    ADCn input pin was close to, equal to, or greater than that on

    VDDA.

    -So it's pretty clear: The result is aligned to the top of the 16-bit word. Your DMA should only transfer 16 bits from the DRx or GDR register.

    The manual also mentions the following, which I believe is important in your case:

    Remark: Use only the individual channel data registers DR0 to DR7 with burst mode or with hardware triggering to read the conversion results.

    Thus the result is in the low 16 bits as follows (in binary): %RRRRRRRRRR000000, where R represents the 10-bit ADC Result.

    So you don't need the AND or any bit-shifting; you get the fractional ADC result.

    That means, when you've found your MIN and MAX values, you could multiply those values by 3.3 and divide by 65536.0, then you have the actual voltage (providing that the ADC reference voltage on the VDDA pin is 3.3V exactly.

    If you prefer using integers (which is of course quicker), you can just multiply by 3300 and shift the result to the right 16 times, then you have millivolts. - but it should not be necessary to use integers in this case, as you'd most likely do that conversion on a PC, which is processing the captured data.

Reply
  • An AND operation will cost 1 clock cycle at least.

    I will expect that it will stay at one clock cycle because the compiler should prepare the AND-mask before the loop starts.

    The ADC, however, should always give you the same bit-values in the upper bits.

    As far as I recall, the LPC4xxx can be configured to shift the bits to the top, which means you should be able to min/max those as most-significant instead of least-significant.

    Thus you would not need to do any shifting or ANDing.

    If the LPC4xxx always insert zeros at the bottom, when in this mode, this might be the most beneficial setting you can get (because the ADC value would be ready for use as a fractional value).

    Even if the lower bits are 'rubbish', you can always clear those bits after the min/max loop, so it won't really cause any slow-down.

    -I decided to investigate things, and in UM10503, section 46.6.2 and section 46.6.4, for GDR and DRx, it says:

    BitDescription
    5:0Reserved. These bits always read as zeroes.
    15:6

    When DONE is 1, this field contains a binary fraction representing

    the voltage on the ADCn pin selected by the SEL field, divided by

    the reference voltage on the VDDA pin. Zero in the field indicates

    that the voltage on the ADCn input pin was less than, equal to, or

    close to that on VSSA, while 0x3FF indicates that the voltage on

    ADCn input pin was close to, equal to, or greater than that on

    VDDA.

    -So it's pretty clear: The result is aligned to the top of the 16-bit word. Your DMA should only transfer 16 bits from the DRx or GDR register.

    The manual also mentions the following, which I believe is important in your case:

    Remark: Use only the individual channel data registers DR0 to DR7 with burst mode or with hardware triggering to read the conversion results.

    Thus the result is in the low 16 bits as follows (in binary): %RRRRRRRRRR000000, where R represents the 10-bit ADC Result.

    So you don't need the AND or any bit-shifting; you get the fractional ADC result.

    That means, when you've found your MIN and MAX values, you could multiply those values by 3.3 and divide by 65536.0, then you have the actual voltage (providing that the ADC reference voltage on the VDDA pin is 3.3V exactly.

    If you prefer using integers (which is of course quicker), you can just multiply by 3300 and shift the result to the right 16 times, then you have millivolts. - but it should not be necessary to use integers in this case, as you'd most likely do that conversion on a PC, which is processing the captured data.

Children