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
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
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
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
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
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
Thanks, that should make a good sanity check to make sure I'm doing this right.