Example of 2-channel ADC with PIT and DMA on K22F?

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

Example of 2-channel ADC with PIT and DMA on K22F?

1,139 Views
scottm
Senior Contributor II

I'm confused by the hardware triggering options for the ADC on the K22F.  I need to sample two ADC channels at a rate governed by a PIT, and have both samples transferred by DMA to their buffers.

I'm not finding a clear description of the process in any one place.  The ADC section is lacking, and the ADCxALTTRGEN bits are described in the SIM section, and the PDB section has more about the triggering, but putting it all together without a coherent description is making my head hurt.

If the PDB is required, my concern there is that (aside from not being sure how to configure this mode) I'm using the PDB to drive DAC conversions already.  The DAC operates independently of the ADCs and will often be running at a different sample rate, and the sample rate may change during operation.  Both the DAC interval value and the modulus value are set for the appropriate DAC sample rate, since the PDB docs say that the PDB timer also resets the DAC interval counter when it rolls over and I want to make sure that it's not causing DAC timing glitches.  This makes me worry that using the PDB for ADC timing as well is going to cause problems.

It looks like I could access the channels I need through separate ADCs, but I'd prefer not to have both ADCs running DMA, since ADC1 is currently used for very infrequent sampling of things like internal temperature and battery voltage.  ADC1 may also be run in fast bursts occasionally to generate entropy for crypto functions and I don't want to have to disrupt audio sampling for that.

Thanks,

Scott

Labels (1)
0 Kudos
6 Replies

789 Views
mjbcswitzerland
Specialist V

Scott

I would be tempted to use a PIT for the DAC; then you have the PDB for the ADCs (using HW triggered mode you can then sample two different channels of a single ADC).
In http://www.utasker.com/docs/uTasker/uTaskerADC.pdf the PIT->DMA->DAC is illustrated (chapter 4) as well as the PDB -> ADC -> DMA (chapter 3).
Beware that PIT DMA triggers are limited (PIT0 can trigger DMA 0, PIT1 can trigger DMA 1 etc).

Regards

Mark

http://www.utasker.com/kinetis/FRDM-K22F.html
http://www.utasker.com/kinetis/TWR-K22F120M.html
http://www.utasker.com/kinetis/BLAZE_K22.html

0 Kudos

789 Views
scottm
Senior Contributor II

I've used PIT-gated DMA transfers before.  The problem I encountered with the DAC is that the only hardware trigger seems to be the PDB.  Without hardware triggering, it needs the software trigger bit set - at least in buffered mode.  Without the buffer enabled, I was getting a garbled signal that I assumed was from a lack of coherency in the register writes.  Have you had success using the DAC with DMA and PIT?  I'd be happy to ditch the DAC buffer - it seems to be causing me more trouble than it's worth.

Scott

0 Kudos

789 Views
mjbcswitzerland
Specialist V

Scott

I don't see any reason for buffered DAC mode if the samples are being written to the DAC at regular intervals.
Here I have a K22 doing USB-Audio to DAC with PIT driven DMA to a loud speaker, and an oscilloscope/spectrum analysis in a display: https://www.youtube.com/watch?v=n-GABeILGV8&feature=youtu.be
and I don't remember ever having any difficulties with the output part (just a little with the use of the CMSIS FFT routines...)

Regards

Mark

This is the API code that I use. Note that the DAC is set for non-buffered + HW triggered mode and only PIT0 can be used to trigger DAC0 (PIT1 for DAC1). I also slightly vary the PIT's frequency (PLL) later to keep it locked to the USB host's data rate otherwise they drift and clicks and buzzes are heard when they are no longer in sync.
As well as in the demo I have also used the same technique to audio processors via I2S for telephone conferencing equipment (on KL parts) in products that have been on the market for a year or so now.

    DAC_SETUP dac_setup;                                                 // DAC configuration parameters
    dac_setup.int_type = DAC_INTERRUPT;
    dac_setup.int_dac_controller = 0;                                    // DAC 0
    dac_setup.int_handler = buffer_wrap;                                 // DMA interrupt handler
    dac_setup.int_priority = 0;                                          // highest priority
    dac_setup.dac_mode = (DAC_ENABLE | DAC_OUTPUT_VALUE | DAC_CONFIGURE | DAC_REF_VDDA | DAC_NON_BUFFERED_MODE | DAC_FULL_BUFFER_DMA); // configure the DAC to use VDDA as reference voltage in non-buffered mode (using DMA, which is initially disabled)
    dac_setup.ptrDAC_Buffer = (unsigned short *)ptrBufIn;                // copy from the USB buffer
    dac_setup.ulDAC_buffer_length = queue_size;                          // the buffer's physical length
    dac_setup.ucDmaChannel = 0;                                          // DMA channel 0 used
    dac_setup.ucDmaTriggerSource = DMAMUX0_DMA0_CHCFG_SOURCE_PIT0;       // PIT0 triggers the channel mux
    dac_setup.dac_mode |= DAC_HW_TRIGGER_MODE;                           // use HW trigger mode rather than SW triggered mode (this requires PIT to trigger it)
    dac_setup.usOutputValue = 0x0800;                                    // prime first value to mid-voltage
    fnConfigureInterrupt((void *)&dac_setup);                            // configure DAC but don't start DMA operation yet (started on USB-audio connection)

    PIT_SETUP pit_setup;                                                 // PIT configuration
    pit_setup.int_type = PIT_INTERRUPT;                                  // configure PIT(s)
    pit_setup.mode = (PIT_PERIODIC);                                     // periodic (DMA) trigger
    pit_setup.ucPIT = 0;                                                 // use PIT0 - for DAC conversion trigger
    pit_setup.int_handler = 0;                                           // no interrupt since the PIT will be used for triggering DMA
    pit_setup.count_delay = PIT_FREERUN_FREQ(48000);                     // 48kHz
    fnConfigureInterrupt((void *)&pit_setup);                            // configure PIT 0 to free-run at 48MHz and trigger DMA copies to the DAC

0 Kudos

789 Views
scottm
Senior Contributor II

I gave it a try with the DAC unbuffered and in DMA mode it seems fine.  I tried it last time in interrupt-driven mode and it was garbled.  DMA is working exactly as expected.

Is your PLL code publicly available?  I'm going to need to implement the same thing to lock the sample rate to an incoming RTP stream for some modes.

Thanks,

Scott

0 Kudos

789 Views
mjbcswitzerland
Specialist V

Scott

The USB audio operation is included in the uTasker Open Source project code.

The PLL uses a second timer to measure the USB frame drift and simply changes the DAC PIT by +/-1 count (maybe +/-2 depending on the drift) if needed. I have described it in chapter 4 of the USB-Audio User's guide at http://www.utasker.com/docs/uTasker/uTaskerUSB_Audio.pdf

Regards

Mark

0 Kudos

789 Views
scottm
Senior Contributor II

Thanks, that should make a good sanity check to make sure I'm doing this right.

0 Kudos