<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>topic Re: Audio double buffering on K66 in Kinetis Microcontrollers</title>
    <link>https://community.nxp.com/t5/Kinetis-Microcontrollers/Audio-double-buffering-on-K66/m-p/700797#M43108</link>
    <description>&lt;HTML&gt;&lt;HEAD&gt;&lt;/HEAD&gt;&lt;BODY&gt;&lt;P&gt;Jeff&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;The K66 has a &lt;STRONG&gt;PDB&lt;/STRONG&gt;&lt;SPAN&gt; which is intended for ADC/DAC timing, rather than the more limited PIT. See chapter 3 in &lt;/SPAN&gt;&lt;A class="jive-link-external-small" href="https://community.nxp.com/external-link.jspa?url=http%3A%2F%2Fwww.utasker.com%2Fdocs%2FuTasker%2FuTaskerADC.pdf" rel="nofollow" target="_blank"&gt;http://www.utasker.com/docs/uTasker/uTaskerADC.pdf&lt;/A&gt;&lt;SPAN&gt; for a reference to do more or less what you are doing.&lt;/SPAN&gt;&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;I have attached binary files for the &lt;STRONG&gt;Teensy 3.6&lt;/STRONG&gt; (hex file actually since the Teensy can't load binary files) and the &lt;STRONG&gt;FRDM-K66F&lt;/STRONG&gt; which sample ADC1_DM0 at 8kHz and transfer the input value to DAC0 output (both 12 bits) using PDB and DMA. It doesn't use any interrupts but can optionally trigger these at half and full buffer intervals in case the content needs to be manipulated. This reference causes a 1s delay between input and output (allowing adequate time for manipulation) but this is just the way that it is configured as reference.&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;I tested that the FRDM-K66F works correctly but, since I don't have a TEENSY-3.6, I couldn't test on the HW but the simulation was OK and I have had confirmation from Teensy 3.6 users that the generated files do (usually) run on it. I put FS USB CDC on the Teens 3.6's USB with a command line menu (in the I/O menu one can view registers with the "md" command so you can also check register content of the DMA and PDB as reference in case you can copy something).&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;As mentioned before you could get the code to do this from the uTasker open source project on GIT hub (you just need to copy some code and not use the complete environment).&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;Note that I only changed one line in the reference code for the Teensy 3.6 &lt;BR /&gt;&lt;STRONG&gt;adc_setup.int_adc_bit = ADC_DM1_SINGLE;&lt;/STRONG&gt;&lt;BR /&gt;to&lt;BR /&gt;&lt;STRONG&gt;adc_setup.int_adc_bit = ADC_DM0_SINGLE;&lt;/STRONG&gt;&lt;BR /&gt;since the K66 doesn't have an ADC1_DM1 input (as various other K parts do).&lt;BR /&gt;Otherwise I took the reference project and enabled TEST_AD_DA in ADC_Timer.h (ensuring SUPPORT_PDB, SUPPORT_DAC and SUPPORT_ADC were also enabled for the respective drivers) and build. On the HW the operation was immediately successful.&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;If you have limited time it makes sense in using more power-ful solutions that you presently use - did you receive your FRDM-K66F board yet?&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;Regards&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;Mark&lt;/P&gt;&lt;/BODY&gt;&lt;/HTML&gt;</description>
    <pubDate>Sat, 21 Oct 2017 14:12:50 GMT</pubDate>
    <dc:creator>mjbcswitzerland</dc:creator>
    <dc:date>2017-10-21T14:12:50Z</dc:date>
    <item>
      <title>Audio double buffering on K66</title>
      <link>https://community.nxp.com/t5/Kinetis-Microcontrollers/Audio-double-buffering-on-K66/m-p/700788#M43099</link>
      <description>&lt;HTML&gt;&lt;HEAD&gt;&lt;/HEAD&gt;&lt;BODY&gt;&lt;P&gt;Hello! I'm trying to implement a block-based audio processor using double buffering on the input and output and I'm getting some unexpected discontinuities in my output signal. I'm using the Arduino IDE Teensy 3.6, which uses the K66 processor, but I have no debugger capability. The configuration of the peripherals is as follows:&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;UL&gt;&lt;LI&gt;ADC0 is hardware triggered by PIT0, which runs at the audio sample rate&lt;/LI&gt;&lt;LI&gt;ADC0 conversion&amp;nbsp;completions trigger&amp;nbsp;transfers on DMA0 from &lt;SPAN&gt;ADC0_RA to dma0_dest_buffer, which is split into halves, input_buffer and proc_buffer&lt;/SPAN&gt;&lt;BR /&gt;&lt;UL&gt;&lt;LI&gt;DMA0 interrupts on major and half major loop, whereupon the pointers to input_buffer and proc_buffer are swapped&lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;&lt;LI&gt;&amp;nbsp;DMA0 is chained to DMA1, which transfers samples to DAC0_DAT0L&amp;nbsp;from dma1_src_buffer, which is split into halves, render_buffer and output_buffer&lt;UL&gt;&lt;LI&gt;DMA1 interrupts on major and half major loop, whereupon the pointers to render_buffer and output_buffer are swapped, and the contents of proc_buffer are copied into render_buffer after scaling the 16-bit ADC readings to 12 bits for the DAC&lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;&lt;/UL&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;The discontinuities are shown in the attached image. Seems that it periodically re-plays samples that have already been sent to the output. The really strange thing is that the spacing of the discontinuities scales&amp;nbsp;with the buffer length, but&amp;nbsp;it's not at the buffer boundaries, as I would expect if I had messed up the double-buffer pointer swaps.&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;For buffer length 4 (83us) , they are spaced at ~650us, or every 8&amp;nbsp;buffers&lt;/P&gt;&lt;P&gt;&lt;SPAN&gt;For buffer length 8 (167us), they are spaced at ~2.6ms, or every 16 buffers&lt;/SPAN&gt;&lt;/P&gt;&lt;P&gt;&lt;SPAN&gt;For buffer length 16 (333us), they are spaced at ~11ms, or every 32 buffers&lt;/SPAN&gt;&lt;/P&gt;&lt;P&gt;&lt;SPAN&gt;For buffer length 32 (667us), they are spaced at ~48ms, or every 64 buffers&lt;/SPAN&gt;&lt;/P&gt;&lt;P&gt;&lt;SPAN&gt;For buffer length 64&amp;nbsp;(&lt;SPAN&gt;1.3ms&lt;/SPAN&gt;&lt;SPAN&gt;), they are spaced at ~170ms, or every 128 buffers&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;Beyond that, the discontinuities are spread so far apart that I can no longer see them on the scope at that time scale. I've been stuck on this problem for a few days, unable to figure out what could be causing that strange pattern. &lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;Lowering the sample rate has no effect. I have also tried filling render_buffer with samples synthesized directly from a wavetable oscillator in dma_ch1_isr(), and I get no discontinuities. I also observe no discontinuities when I print samples from proc_buffer to Arduino's serial plotter from dma_ch0_isr(), so I believe the problem lies somewhere in the DMA transfers or double buffer handling.&amp;nbsp;&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;Any help is greatly appreciated. Code shown below:&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;#define BAUD_RATE (230400)&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;#define SAMPLE_RATE (48000.0f)&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;#define PIT_PERIOD ((uint32_t)(F_BUS / SAMPLE_RATE)-1)&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;#define BUFFER_LEN (16)&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;#define ADC_RES (16)&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;#define DAC_RES (12)&lt;/SPAN&gt;&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;static volatile uint16_t dma0_dest_buffer[2*BUFFER_LEN];&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;static volatile uint16_t * input_buffer = &amp;amp;dma0_dest_buffer[0];&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;static volatile uint16_t * proc_buffer = &amp;amp;dma0_dest_buffer[BUFFER_LEN];&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;static volatile uint16_t dma1_src_buffer[2*BUFFER_LEN];&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;static volatile uint16_t * render_buffer = &amp;amp;dma1_src_buffer[BUFFER_LEN];&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;static volatile uint16_t * output_buffer = &amp;amp;dma1_src_buffer[0];&lt;/SPAN&gt;&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;// See table 39.1.3.1 for pin mapping&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;int ch = 5; // ADC0 channel 5 =&amp;gt; AD4b, input signal ADC0_SE4b&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;// (Mapped to pin A0 on Teensy 3.6)&lt;/SPAN&gt;&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;void setup() {&lt;/SPAN&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; Serial.begin(BAUD_RATE);&lt;/SPAN&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;// Initialize DMA1 source buffer&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; for (int i = 0; i &amp;lt; 2*BUFFER_LEN; i++) {&lt;/SPAN&gt;&lt;/P&gt;&lt;P style="padding-left: 60px;"&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; dma0_dest_buffer[i] = (1 &amp;lt;&amp;lt; ADC_RES) / 2;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; dma1_src_buffer[i] = (1 &amp;lt;&amp;lt; DAC_RES) / 2;&lt;/SPAN&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; }&lt;/SPAN&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;init_adc0();&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; init_dac0();&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; init_dma();&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; init_pit0();&lt;/SPAN&gt;&lt;/P&gt;&lt;P&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;}&lt;/SPAN&gt;&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;void init_adc0() {&lt;/SPAN&gt;&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;// (13.2.16) System clock gating control register 6&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; SIM_SCGC6 |= SIM_SCGC6_ADC0; // Enable ADC0 clock&lt;/SPAN&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;// (39.4.2) ADC Configuration Register 1&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; ADC0_CFG1 |= ADC_CFG1_ADICLK(0); // Input clock = Bus clock&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; ADC0_CFG1 |= ADC_CFG1_MODE(3); // Single-ended, 16-bit&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; ADC0_CFG1 &amp;amp;= ~ADC_CFG1_ADLSMP; // Short sample time&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; ADC0_CFG1 |= ADC_CFG1_ADIV(1); // Input clock / 2&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; ADC0_CFG1 &amp;amp;= ~ADC_CFG1_ADLPC; // Normal power configuration&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; // ADC Clock = F_BUS / 2 = 30MHz&lt;/SPAN&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;// (39.4.3) ADC Configuration Register 2&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; ADC0_CFG2 |= ADC_CFG2_ADLSTS(2); // 6 extra ADCK cycles, 10 total sample time&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; ADC0_CFG2 &amp;amp;= ~ADC_CFG2_ADHSC; // Normal speed conversion&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; ADC0_CFG2 |= ADC_CFG2_MUXSEL; // ADxxB channels are selected (See table 39.1.3.1)&lt;/SPAN&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;// (39.4.6) Status and Control Register 2&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; ADC0_SC2 |= ADC_SC2_REFSEL(0); // Voltage reference = Vcc&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; ADC0_SC2 |= ADC_SC2_DMAEN; // Enable DMA&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; ADC0_SC2 &amp;amp;= ~ADC_SC2_ACREN; // Disable comp. function range&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; ADC0_SC2 &amp;amp;= ~ADC_SC2_ACFGT; // Disable comp. function greater than&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; ADC0_SC2 &amp;amp;= ~ADC_SC2_ACFE; // Disable comp. function&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; ADC0_SC2 &amp;amp;= ~ADC_SC2_ADTRG; // Software trigger (for calibration)&lt;/SPAN&gt;&lt;BR /&gt; &lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; // (39.4.6) Status and Control Register 3&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; ADC0_SC3 |= ADC_SC3_AVGS(0); // Hardware average 4 samples&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; ADC0_SC3 |= ADC_SC3_AVGE; // Enable hardware averaging&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; ADC0_SC3 &amp;amp;= ~ADC_SC3_ADCO; // Single conversion&lt;/SPAN&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;// Run calibration&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; adc_calibrate();&lt;/SPAN&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;// (39.4.6) Status and Control Register 2&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; ADC0_SC2 |= ADC_SC2_ADTRG; // Enable hardware trigger&lt;/SPAN&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;// (13.2.7) System options register 7&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; SIM_SOPT7 |= SIM_SOPT7_ADC0ALTTRGEN; // Alt trigger select&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; SIM_SOPT7 |= SIM_SOPT7_ADC0TRGSEL(4); // PIT trigger 0 select&lt;/SPAN&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;// (39.4.1) ADC Status and Control Registers 1 (ADCx_SC1n)&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; uint32_t sc1a_config;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; sc1a_config |= ADC_SC1_ADCH(ch); // Channel selection&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; sc1a_config &amp;amp;= ~ADC_SC1_DIFF; // Single-ended mode&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; sc1a_config &amp;amp;= ~ADC_SC1_AIEN; // Disable interrupts&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; ADC0_SC1A = sc1a_config;&lt;/SPAN&gt;&lt;/P&gt;&lt;P&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;}&lt;/SPAN&gt;&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;void adc_calibrate() {&lt;/SPAN&gt;&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;uint16_t sum;&lt;/SPAN&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;ADC0_SC3 |= ADC_SC3_CAL; // Initiate automatic calibration sequence&lt;/SPAN&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;while (ADC0_SC3 &amp;amp; ADC_SC3_CAL) {/* wait for it... */}&lt;/SPAN&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;if (ADC0_SC3 &amp;amp; ADC_SC3_CALF)&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;Serial.println("Calibration Failed");&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; else&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;Serial.println("Calibration Successful");&lt;/SPAN&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;// Plus-side gain calibration&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; sum = (ADC0_CLP0 + ADC0_CLP1 + ADC0_CLP2 + ADC0_CLP3 + ADC0_CLP4 + ADC0_CLPS) &amp;gt;&amp;gt; 1;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; sum |= (1 &amp;lt;&amp;lt; 15);&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; ADC0_PG = sum;&lt;/SPAN&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;// Minus-side gain calibration&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; sum = (ADC0_CLMS + ADC0_CLM4 + ADC0_CLM3 + ADC0_CLM2 + ADC0_CLM1 + ADC0_CLM0) &amp;gt;&amp;gt; 1;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; sum |= (1 &amp;lt;&amp;lt; 15);&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; ADC0_MG = sum;&lt;/SPAN&gt;&lt;/P&gt;&lt;P&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;}&lt;/SPAN&gt;&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;void init_dac0() {&lt;/SPAN&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; // (13.2.12) System clock gating control regi&lt;/SPAN&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;ster 2&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; SIM_SCGC2 |= SIM_SCGC2_DAC0; // Enable DAC0 clock&lt;/SPAN&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;// (41.5.4) DAC Control Register 0 &lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; DAC0_C0 |= DAC_C0_DACEN; // Enable DAC&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; DAC0_C0 |= DAC_C0_DACRFS; // Select DACREF_2 (3.3V) &lt;/SPAN&gt;&lt;/P&gt;&lt;P&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;}&lt;/SPAN&gt;&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;void init_pit0() {&lt;/SPAN&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; SIM_SCGC6 |= SIM_SCGC6_PIT; // (13.2.16) Send system clock to PIT&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; PIT_MCR = 0x00; // (46.4.1) Turn on PIT &lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; PIT_LDVAL0 = PIT_PERIOD; // (46.4.4) Set timer 0 period&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; PIT_TCTRL0 |= PIT_TCTRL_TEN; // (46.4.6) Enable timer 0&lt;/SPAN&gt;&lt;/P&gt;&lt;P&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;}&lt;/SPAN&gt;&lt;/P&gt;&lt;P&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;&lt;P&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;void init_dma() {&lt;/SPAN&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; // (13.2.16-17) System clock gating control registers 6 and 7&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; SIM_SCGC6 |= SIM_SCGC6_DMAMUX; // Enable DMAMUX clock&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; SIM_SCGC7 |= SIM_SCGC7_DMA; // Enable DMA clock&lt;/SPAN&gt;&lt;BR /&gt; &lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; // (24.3.1) Control Register&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; DMA_CR |= DMA_CR_EMLM; // Enable minor loop mapping&lt;/SPAN&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;init_dma0();&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; init_dma1(); &lt;/SPAN&gt;&lt;/P&gt;&lt;P&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;}&lt;/SPAN&gt;&lt;/P&gt;&lt;P&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;&lt;P&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;void init_dma0() {&lt;/SPAN&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; /* === Source === */&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; // (24.3.18) TCD Source Address &lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; DMA_TCD0_SADDR = (volatile uint16_t *)&amp;amp;ADC0_RA; &lt;/SPAN&gt;&lt;BR /&gt; &lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; // (24.3.20) TCD Transfer Attributes &lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; DMA_TCD0_ATTR = 0x0000;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; DMA_TCD0_ATTR |= DMA_TCD_ATTR_SSIZE(1); // Source data transfer size (16-bit) &lt;/SPAN&gt;&lt;BR /&gt; &lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; // (24.3.19) TCD Signed Source Address Offset&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; DMA_TCD0_SOFF = 0; // Don't advance source pointer after minor loop &lt;/SPAN&gt;&lt;BR /&gt; &lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; // (24.3.23) TCD Signed Minor Loop Offset (Minor Loop Enabled and Offset Enabled)&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; DMA_TCD0_NBYTES_MLOFFYES = sizeof(uint16_t); // 2 bytes per minor loop&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; DMA_TCD0_NBYTES_MLOFFYES &amp;amp;= ~DMA_TCD_NBYTES_SMLOE; // Source minor loop offset disable (src)&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; DMA_TCD0_NBYTES_MLOFFYES |= DMA_TCD_NBYTES_DMLOE; // Source minor loop offset enable (dest)&lt;/SPAN&gt;&lt;BR /&gt; &lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; // TCD Current Minor Loop Link, Major Loop Count&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; DMA_TCD0_BITER_ELINKYES = sizeof(dma0_dest_buffer) / sizeof(uint16_t); // (24.3.32) Begining count&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; DMA_TCD0_BITER_ELINKYES |= DMA_TCD_BITER_ELINKYES_ELINK;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; DMA_TCD0_BITER_ELINKYES |= DMA_TCD_BITER_ELINKYES_LINKCH(1);&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; DMA_TCD0_CITER_ELINKYES = sizeof(dma0_dest_buffer) / sizeof(uint16_t); // (24.3.28) Current count&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; DMA_TCD0_CITER_ELINKYES |= DMA_TCD_CITER_ELINKYES_ELINK;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; DMA_TCD0_CITER_ELINKYES |= DMA_TCD_CITER_ELINKYES_LINKCH(1);&lt;/SPAN&gt;&lt;BR /&gt; &lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; // (24.3.24) TCD Last Source Address Adjustment &lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; DMA_TCD0_SLAST = 0; // Don't advance source pointer after major loop&lt;/SPAN&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;/* === Destination === */&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; // (21.3.24) TCD Destination Address &lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; DMA_TCD0_DADDR = (volatile uint16_t *)&amp;amp;dma0_dest_buffer;&lt;/SPAN&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;// (24.3.20) TCD Transfer Attributes &lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; DMA_TCD0_ATTR |= DMA_TCD_ATTR_DSIZE(1); // Destination data transfer size (16-bit)&lt;/SPAN&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;// (24.3.26) TCD Signed Destination Address Offset &lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; DMA_TCD0_DOFF = sizeof(uint16_t); // Advance dest pointer by 2 bytes per value&lt;/SPAN&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;// (24.3.29) TCD Last Destination Address Adjustment/Scatter Gather Address &lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; DMA_TCD0_DLASTSGA = -sizeof(dma0_dest_buffer); // Return to &amp;amp;dma_dest_buffer[0] after major loop&lt;/SPAN&gt;&lt;BR /&gt; &lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; /* === Interrupts === */&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; // (24.3.30) TCD Control and Status&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; DMA_TCD0_CSR |= DMA_TCD_CSR_INTMAJOR; // Interrupt at major loop (CITER == 0)&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; DMA_TCD0_CSR |= DMA_TCD_CSR_INTHALF; // Also interrupt at half major loop (CITER == BITER/2)&lt;/SPAN&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;// (24.3.8) Set Enable Request Register &lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; DMA_SERQ |= DMA_SERQ_SERQ(0); // Enable channel 0 DMA requests&lt;/SPAN&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;NVIC_ENABLE_IRQ(IRQ_DMA_CH0); // Enable interrupt request line for DMA channel 0&lt;/SPAN&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;/* === Triggering === */ &lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; // (23.4.1) Channel Configuration Register &lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; DMAMUX0_CHCFG0 = DMAMUX_SOURCE_ADC0; // Trigger after ADC0 transfers&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; DMAMUX0_CHCFG0 |= DMAMUX_ENABLE; // DMA channel enable &lt;/SPAN&gt;&lt;/P&gt;&lt;P&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;}&lt;/SPAN&gt;&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;void init_dma1() {&lt;/SPAN&gt;&lt;/P&gt;&lt;P&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;/* === Source === */&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; // (24.3.18) TCD Source Address &lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; DMA_TCD1_SADDR = (volatile uint16_t *)&amp;amp;dma1_src_buffer; &lt;/SPAN&gt;&lt;BR /&gt; &lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; // (24.3.20) TCD Transfer Attributes &lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; DMA_TCD1_ATTR = 0x0000;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; DMA_TCD1_ATTR |= DMA_TCD_ATTR_SSIZE(1); // Source data transfer size (16-bit) &lt;/SPAN&gt;&lt;BR /&gt; &lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; // (24.3.19) TCD Signed Source Address Offset&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; DMA_TCD1_SOFF = sizeof(uint16_t); // Advance source pointer by 2 bytes per value &lt;/SPAN&gt;&lt;BR /&gt; &lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; // (24.3.23) TCD Signed Minor Loop Offset (Minor Loop Enabled and Offset Enabled)&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; DMA_TCD1_NBYTES_MLOFFYES = sizeof(uint16_t); // 2 bytes per minor loop&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; DMA_TCD1_NBYTES_MLOFFYES |= DMA_TCD_NBYTES_SMLOE; // Src. minor loop offset enable&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; DMA_TCD0_NBYTES_MLOFFYES &amp;amp;= ~DMA_TCD_NBYTES_DMLOE; // Dest. minor loop offset disable&lt;/SPAN&gt;&lt;BR /&gt; &lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; // TCD Current Minor Loop Link, Major Loop Count&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; DMA_TCD1_BITER_ELINKNO = sizeof(dma1_src_buffer) / sizeof(uint16_t); // (24.3.32) Begining count&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; DMA_TCD1_CITER_ELINKNO = sizeof(dma1_src_buffer) / sizeof(uint16_t); // (24.3.28) Current count&lt;/SPAN&gt;&lt;BR /&gt; &lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; // (24.3.24) TCD Last Source Address Adjustment &lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; DMA_TCD1_SLAST = -sizeof(dma1_src_buffer); // Return to &amp;amp;dma1_src_buffer[0] after major loop&lt;/SPAN&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;/* === Destination === */&lt;/SPAN&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;// (21.3.24) TCD Destination Address &lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; DMA_TCD1_DADDR = (volatile uint16_t *)&amp;amp;DAC0_DAT0L;&lt;/SPAN&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;// (24.3.20) TCD Transfer Attributes &lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; DMA_TCD1_ATTR |= DMA_TCD_ATTR_DSIZE(1); // Destination data transfer size (16-bit)&lt;/SPAN&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;// (24.3.26) TCD Signed Destination Address Offset &lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; DMA_TCD1_DOFF = 0;&lt;/SPAN&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;// (24.3.29) TCD Last Destination Address Adjustment/Scatter Gather Address &lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; DMA_TCD1_DLASTSGA = 0;&lt;/SPAN&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;/* === Interrupts === */&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; // (24.3.30) TCD Control and Status &lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; DMA_TCD1_CSR |= DMA_TCD_CSR_INTMAJOR; // Interrupt at major loop (CITER == 0)&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; DMA_TCD1_CSR |= DMA_TCD_CSR_INTHALF; // Also interrupt at half major loop (CITER == BITER/2)&lt;/SPAN&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;// (24.3.8) Set Enable Request Register &lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; DMA_SERQ |= DMA_SERQ_SERQ(1); // Enable channel 1 DMA requests&lt;/SPAN&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;NVIC_ENABLE_IRQ(IRQ_DMA_CH1); // Enable interrupt request line for DMA channel 1&lt;/SPAN&gt;&lt;/P&gt;&lt;P&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;}&lt;/SPAN&gt;&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;void loop() {}&lt;/SPAN&gt;&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;void dma_ch0_isr(void) {&lt;/SPAN&gt;&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;// Swap pointers to input and proc buffers&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; static volatile uint16_t * tmp;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; tmp = input_buffer;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; input_buffer = proc_buffer;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; proc_buffer = tmp;&lt;/SPAN&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;DMA_CINT = DMA_CINT_CINT(0); // (24.3.12) Clear interrupt request register&lt;/SPAN&gt;&lt;/P&gt;&lt;P&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;}&lt;/SPAN&gt;&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;void dma_ch1_isr(void) {&lt;/SPAN&gt;&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;// Swap pointers to output and render buffers&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; static volatile uint16_t * tmp;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; tmp = output_buffer;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; output_buffer = render_buffer;&lt;/SPAN&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; render_buffer = tmp;&lt;/SPAN&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;// Copy samples to render_buffer&lt;/SPAN&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;for (int i = 0; i &amp;lt; BUFFER_LEN; i++) {&lt;/SPAN&gt;&lt;/P&gt;&lt;P style="padding-left: 60px;"&gt;&lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; render_buffer[i] = proc_buffer[i] &amp;gt;&amp;gt; (ADC_RES - DAC_RES);&lt;/SPAN&gt;&lt;/P&gt;&lt;P style="padding-left: 30px;"&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; }&lt;/SPAN&gt;&lt;BR /&gt; &lt;BR /&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt; DMA_CINT = DMA_CINT_CINT(1); // (24.3.12) Clear interrupt request register&lt;/SPAN&gt;&lt;/P&gt;&lt;P&gt;&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;}&lt;/SPAN&gt;&lt;/P&gt;&lt;/BODY&gt;&lt;/HTML&gt;</description>
      <pubDate>Fri, 06 Oct 2017 21:51:10 GMT</pubDate>
      <guid>https://community.nxp.com/t5/Kinetis-Microcontrollers/Audio-double-buffering-on-K66/m-p/700788#M43099</guid>
      <dc:creator>jeffgregorio</dc:creator>
      <dc:date>2017-10-06T21:51:10Z</dc:date>
    </item>
    <item>
      <title>Re: Audio double buffering on K66</title>
      <link>https://community.nxp.com/t5/Kinetis-Microcontrollers/Audio-double-buffering-on-K66/m-p/700789#M43100</link>
      <description>&lt;HTML&gt;&lt;HEAD&gt;&lt;/HEAD&gt;&lt;BODY&gt;&lt;P&gt;Hi Jeff&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;There is a double-buffered DMA based reference for your processor in the Open Source uTasker project on GIT hub. It will also run the code (with interrupt and DMA emulation) in Visual Studio so that you can analyse the behavior and correct anything needed in your source. It will also record to SD card and there is a USB-Audio reference using PIT0 to double-buffered USB.&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;Documents:&lt;BR /&gt;&lt;SPAN&gt;- &lt;/SPAN&gt;&lt;A class="jive-link-external-small" href="https://community.nxp.com/external-link.jspa?url=http%3A%2F%2Fwww.utasker.com%2Fdocs%2FuTasker%2FuTaskerADC.pdf" rel="nofollow" target="_blank"&gt;http://www.utasker.com/docs/uTasker/uTaskerADC.pdf&lt;/A&gt;&lt;BR /&gt;&lt;SPAN&gt;- &lt;/SPAN&gt;&lt;A class="jive-link-external-small" href="https://community.nxp.com/external-link.jspa?url=http%3A%2F%2Fwww.utasker.com%2Fdocs%2FuTasker%2FuTaskerUSB_Audio.pdf" rel="nofollow" target="_blank"&gt;http://www.utasker.com/docs/uTasker/uTaskerUSB_Audio.pdf&lt;/A&gt;&lt;BR /&gt;&lt;SPAN&gt;Code: &lt;/SPAN&gt;&lt;A class="jive-link-external-small" href="https://community.nxp.com/external-link.jspa?url=http%3A%2F%2Fwww.utasker.com%2Fkinetis.html" rel="nofollow" target="_blank"&gt;http://www.utasker.com/kinetis.html&lt;/A&gt;&lt;BR /&gt;References for K66&lt;BR /&gt;&lt;SPAN&gt;- &lt;/SPAN&gt;&lt;A class="jive-link-external-small" href="https://community.nxp.com/external-link.jspa?url=http%3A%2F%2Fwww.utasker.com%2Fkinetis%2FTWR-K65F180M.html" rel="nofollow" target="_blank"&gt;http://www.utasker.com/kinetis/TWR-K65F180M.html&lt;/A&gt;&lt;BR /&gt;&lt;SPAN&gt;- &lt;/SPAN&gt;&lt;A class="jive-link-external-small" href="https://community.nxp.com/external-link.jspa?url=http%3A%2F%2Fwww.utasker.com%2Fkinetis%2FFRDM-K66F.html" rel="nofollow" target="_blank"&gt;http://www.utasker.com/kinetis/FRDM-K66F.html&lt;/A&gt;&lt;BR /&gt;&lt;SPAN&gt;- &lt;/SPAN&gt;&lt;A class="jive-link-external-small" href="https://community.nxp.com/external-link.jspa?url=http%3A%2F%2Fwww.utasker.com%2Fkinetis%2FTEENSY_3.6.html" rel="nofollow" target="_blank"&gt;http://www.utasker.com/kinetis/TEENSY_3.6.html&lt;/A&gt;&lt;SPAN&gt; (also for direct operation on Teensy 3.6)&lt;/SPAN&gt;&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;&lt;BR /&gt;I would get a FRDM-K66F (it is not much more expensive than a Teensy 3.6 but has much more HW to play with and an inbuilt debugger). This will allow you to work efficiently and then you can put the confirmed code back into your Arduino environment to run on the Teensy. Developing on a Teensy directly is really only for people who like spending days solving quite simple problems that FRDM-K66F users will be able to work out quite simply - with simulation as well you may be able to increase your development efficiency by at least a factor of 10.&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;Regards&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;Mark&lt;/P&gt;&lt;/BODY&gt;&lt;/HTML&gt;</description>
      <pubDate>Sat, 07 Oct 2017 15:10:57 GMT</pubDate>
      <guid>https://community.nxp.com/t5/Kinetis-Microcontrollers/Audio-double-buffering-on-K66/m-p/700789#M43100</guid>
      <dc:creator>mjbcswitzerland</dc:creator>
      <dc:date>2017-10-07T15:10:57Z</dc:date>
    </item>
    <item>
      <title>Re: Audio double buffering on K66</title>
      <link>https://community.nxp.com/t5/Kinetis-Microcontrollers/Audio-double-buffering-on-K66/m-p/700790#M43101</link>
      <description>&lt;HTML&gt;&lt;HEAD&gt;&lt;/HEAD&gt;&lt;BODY&gt;&lt;P&gt;Hi, Jeff,&lt;/P&gt;&lt;P&gt;I have checked the register setting, I think it is okay.&lt;/P&gt;&lt;P&gt;But maybe I am not clear about your code, it seems that ping-pong buffer is NOT used by DMA, because you do not reconfigure DMA in DMA ISR. In the case, I suggest you disable INTHALF interrupt, just use the INTMAJOR interrupt. For the two DMA channel, just use one channel interrupt for example just use DMA1 interrupt, in the ISR, just scale the ADC sample buffer and copy the sample buffer array&amp;nbsp; to DAC buffer array. What is the result?&lt;/P&gt;&lt;P&gt;BR&lt;/P&gt;&lt;P&gt;Xiangjun Rong&lt;/P&gt;&lt;/BODY&gt;&lt;/HTML&gt;</description>
      <pubDate>Wed, 11 Oct 2017 08:24:07 GMT</pubDate>
      <guid>https://community.nxp.com/t5/Kinetis-Microcontrollers/Audio-double-buffering-on-K66/m-p/700790#M43101</guid>
      <dc:creator>xiangjun_rong</dc:creator>
      <dc:date>2017-10-11T08:24:07Z</dc:date>
    </item>
    <item>
      <title>Re: Audio double buffering on K66</title>
      <link>https://community.nxp.com/t5/Kinetis-Microcontrollers/Audio-double-buffering-on-K66/m-p/700791#M43102</link>
      <description>&lt;HTML&gt;&lt;HEAD&gt;&lt;/HEAD&gt;&lt;BODY&gt;&lt;P&gt;I'm not sure what Rong is trying to say --- using ONE contiguous buffer with TWO interrupts as the DMA engine re-cycles is a GREAT way to implement 'ping' and 'pong' memory areas without needing to reconfigure ANY DMA registers 'on the fly'.&amp;nbsp; There is no logical reason to expect running the DMA in a 'more complicated way' (such as the suggested continuous modifications, OR with a chained-pair of control descriptors) will affect your timing issue.&lt;/P&gt;&lt;/BODY&gt;&lt;/HTML&gt;</description>
      <pubDate>Wed, 11 Oct 2017 10:19:12 GMT</pubDate>
      <guid>https://community.nxp.com/t5/Kinetis-Microcontrollers/Audio-double-buffering-on-K66/m-p/700791#M43102</guid>
      <dc:creator>egoodii</dc:creator>
      <dc:date>2017-10-11T10:19:12Z</dc:date>
    </item>
    <item>
      <title>Re: Audio double buffering on K66</title>
      <link>https://community.nxp.com/t5/Kinetis-Microcontrollers/Audio-double-buffering-on-K66/m-p/700792#M43103</link>
      <description>&lt;HTML&gt;&lt;HEAD&gt;&lt;/HEAD&gt;&lt;BODY&gt;&lt;P&gt;Yes, I was a bit confused as well, but I think&amp;nbsp;Rong is suggesting that I use 1 DMA channel to transfer ADC results, and using that channel's interrupt to copy those results into the DAC's hardware buffer. That's not an ideal solution for me, as I would have to make the incoming buffer's length match the length of the DAC buffer, and I'd like to be able to vary the buffer length for different latencies.&amp;nbsp;&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;However, I do think there may be something to using chained-pair control descriptors for the DMA, and here's the reason:&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;I discovered that my discontinuities may be resulting from timing drift between the interrupts on the two DMA channels. I'm now measuring the timing in microseconds between dma_ch0_isr() and dma_ch1_isr(), and printing it out in dma_ch1_isr(). They start out synchronized (called between 0 and 1 microseconds of each other), then drift, then re-synchronize. This occurs at the exact period of the discontinuities.&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;The sequence for BUFFER_LEN = 16 is&lt;/P&gt;&lt;P&gt;{0, 21, 21, 41, 42, 63, 62, 83, 84, 104, 104, 125, 125, 146, 146, 166, 167, 188, 187, 208, 209, 229, 229, 250, 250, 271, 271, 291, 292, 313, 312}&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;I have no idea what's causing this,&amp;nbsp;but using chained TCDs might help. Going to try this as soon as I can.&amp;nbsp;&lt;/P&gt;&lt;/BODY&gt;&lt;/HTML&gt;</description>
      <pubDate>Wed, 11 Oct 2017 20:54:04 GMT</pubDate>
      <guid>https://community.nxp.com/t5/Kinetis-Microcontrollers/Audio-double-buffering-on-K66/m-p/700792#M43103</guid>
      <dc:creator>jeffgregorio</dc:creator>
      <dc:date>2017-10-11T20:54:04Z</dc:date>
    </item>
    <item>
      <title>Re: Audio double buffering on K66</title>
      <link>https://community.nxp.com/t5/Kinetis-Microcontrollers/Audio-double-buffering-on-K66/m-p/700793#M43104</link>
      <description>&lt;HTML&gt;&lt;HEAD&gt;&lt;/HEAD&gt;&lt;BODY&gt;&lt;P&gt;Thanks, Mark. I've taken your suggestion and ordered a FRDM-K66F, but I'm not sure how soon I'll get to learning a new development environment since this is a personal project and I'm squeezing it in around work.&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;For now I'm still troubleshooting in the Arduino IDE, and I've narrowed the source of the problem down a bit further, as detailed in my reply to Earl Goodrich below.&amp;nbsp;&lt;/P&gt;&lt;/BODY&gt;&lt;/HTML&gt;</description>
      <pubDate>Wed, 11 Oct 2017 20:59:20 GMT</pubDate>
      <guid>https://community.nxp.com/t5/Kinetis-Microcontrollers/Audio-double-buffering-on-K66/m-p/700793#M43104</guid>
      <dc:creator>jeffgregorio</dc:creator>
      <dc:date>2017-10-11T20:59:20Z</dc:date>
    </item>
    <item>
      <title>Re: Audio double buffering on K66</title>
      <link>https://community.nxp.com/t5/Kinetis-Microcontrollers/Audio-double-buffering-on-K66/m-p/700794#M43105</link>
      <description>&lt;HTML&gt;&lt;HEAD&gt;&lt;/HEAD&gt;&lt;BODY&gt;&lt;P&gt;Sorry, with the title I was off into the DMA process, but simply 'assumed' that you had inherent rate-lock between the input and the output, based on some 'common clock source' and 'calculable dividers' that would insure coordinated in/out buffer use - but rate-slip is certainly the more obvious issue!&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;I see you have the ADC triggered by PIT0, running 48KHz, and presumably an ADC COCO comes 'soon thereafter' at the same 48KHz, triggering each DMA0 (in).&amp;nbsp; BUT I don't see what triggers DMA1 to pace-out samples -- I expected to see PIT1 set up for this, and &lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;DMAMUX0_CHCFG1 = DMAMUX_TRIG | DMAMUX_ENABLE; &lt;/SPAN&gt;--- OR swap DMA0 and DMA1 usage throughout and double-use the same PIT0 (or, I suppose, vice-versa:&amp;nbsp; Leave DMA 'as is' and use PIT1 throughout including &lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;SIM_SOPT7_ADC0TRGSEL(5)&lt;/SPAN&gt;).&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;I will note that you call out a 30MHz ADC clock, while the K66-180 is limited to 12MHz in 16-bit mode.&amp;nbsp; On a related note, you should know that if you just run the ADC in 12-bit mode, the right-justified result-register will already be in the right position for DAC0_DAT0, AND in that mode the conversion clock can be up to 24MHz.&amp;nbsp; And anything over 8MHz is 'high speed' (&lt;SPAN style="font-family: terminal, monaco, monospace;"&gt;ADC_CFG2_ADHSC&lt;/SPAN&gt;).&lt;/P&gt;&lt;/BODY&gt;&lt;/HTML&gt;</description>
      <pubDate>Thu, 12 Oct 2017 02:44:38 GMT</pubDate>
      <guid>https://community.nxp.com/t5/Kinetis-Microcontrollers/Audio-double-buffering-on-K66/m-p/700794#M43105</guid>
      <dc:creator>egoodii</dc:creator>
      <dc:date>2017-10-12T02:44:38Z</dc:date>
    </item>
    <item>
      <title>Re: Audio double buffering on K66</title>
      <link>https://community.nxp.com/t5/Kinetis-Microcontrollers/Audio-double-buffering-on-K66/m-p/700795#M43106</link>
      <description>&lt;HTML&gt;&lt;HEAD&gt;&lt;/HEAD&gt;&lt;BODY&gt;&lt;P&gt;So before I had the DMA channels linked&amp;nbsp;so DMA0 transfers would initiate DMA1 transfers, so the common clock source was&amp;nbsp;PIT0. I suppose now that this doesn't guarantee synchronization, but I'm still not sure why.&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;I was unaware that a PIT channel could be used to trigger multiple peripherals, but I tried both of your suggestions. I tried:&lt;/P&gt;&lt;P&gt;1) PIT0 triggers ADC0. ADC0 conversions trigger DMA1, which moves the ADC result to the input buffer. PIT0 also triggers DMA0, which moves samples from the buffer to DAC0.&lt;/P&gt;&lt;P&gt;2) PIT0 triggers ADC0 and ADC0 triggers DMA0. PIT1 triggers DMA1, which moves samples from the buffer to the DAC.&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;In both cases I'm getting some unexpected behavior, namely that&amp;nbsp;the DMA channel handing output runs twice as often as the DMA channel handling input, so now it's outputting each buffer twice, but at least the rate-slip looks like it might be gone.&amp;nbsp;&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;In the case where I'm using two PIT channels, the PIT itself is running at twice the rate (tested by enabling PIT interrupts), even though their LDVALs are the same. I tried a hack, setting the LDVAL of the PIT channel used for output to twice the LDVAL of the other, but I still get rate-slip, albeit much less often than before.&amp;nbsp;&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;Thank you for highlighting the issue with my ADC settings, which I've corrected. However the problem with the DMA transfers persists.&amp;nbsp;&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;I've gone over the code so many times over a week, and I'm stumped. Someone in another thread (&lt;A href="https://community.nxp.com/thread/102320"&gt;https://community.nxp.com/thread/102320&lt;/A&gt;&amp;nbsp;) mentioned a "bug in the silicon" related to PIT-triggered DMA transfers, so I'm about ready to abandon this configuration, even though it seems like the most straightforward way to implement double-buffering.&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;I'm also having DMA channels completely crap out on me after uploading code (their interrupts don't fire). It seems DMA0 always works, without exception, but I've had to make alternate versions that use DMA1, 2, and 3 for the second channel. Sometimes 0 and 3 work, and 1 and 2 don't. Sometimes 0 and 2 work, and 1 and 3 don't. In one case, 0, 1, and 2 worked while 3 didn't.&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;Is it possible there is something wrong with the Teensy bootloader, or would this more likely be a hardware defect?&amp;nbsp;&lt;/P&gt;&lt;/BODY&gt;&lt;/HTML&gt;</description>
      <pubDate>Fri, 20 Oct 2017 21:44:26 GMT</pubDate>
      <guid>https://community.nxp.com/t5/Kinetis-Microcontrollers/Audio-double-buffering-on-K66/m-p/700795#M43106</guid>
      <dc:creator>jeffgregorio</dc:creator>
      <dc:date>2017-10-20T21:44:26Z</dc:date>
    </item>
    <item>
      <title>Re: Audio double buffering on K66</title>
      <link>https://community.nxp.com/t5/Kinetis-Microcontrollers/Audio-double-buffering-on-K66/m-p/700796#M43107</link>
      <description>&lt;HTML&gt;&lt;HEAD&gt;&lt;/HEAD&gt;&lt;BODY&gt;&lt;P&gt;Jeff&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;If DMA interrupts don't fire it will usually be due to a DMA error taking place, which aborts the transfer and so it never completes - and this no interrupt.&lt;/P&gt;&lt;P&gt;You will need to observe the DMA status and error registers since they will inform you of the channel that fails and the general cause (eg. source or destination).&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;Regards&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;Mark&lt;/P&gt;&lt;/BODY&gt;&lt;/HTML&gt;</description>
      <pubDate>Sat, 21 Oct 2017 13:39:26 GMT</pubDate>
      <guid>https://community.nxp.com/t5/Kinetis-Microcontrollers/Audio-double-buffering-on-K66/m-p/700796#M43107</guid>
      <dc:creator>mjbcswitzerland</dc:creator>
      <dc:date>2017-10-21T13:39:26Z</dc:date>
    </item>
    <item>
      <title>Re: Audio double buffering on K66</title>
      <link>https://community.nxp.com/t5/Kinetis-Microcontrollers/Audio-double-buffering-on-K66/m-p/700797#M43108</link>
      <description>&lt;HTML&gt;&lt;HEAD&gt;&lt;/HEAD&gt;&lt;BODY&gt;&lt;P&gt;Jeff&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;The K66 has a &lt;STRONG&gt;PDB&lt;/STRONG&gt;&lt;SPAN&gt; which is intended for ADC/DAC timing, rather than the more limited PIT. See chapter 3 in &lt;/SPAN&gt;&lt;A class="jive-link-external-small" href="https://community.nxp.com/external-link.jspa?url=http%3A%2F%2Fwww.utasker.com%2Fdocs%2FuTasker%2FuTaskerADC.pdf" rel="nofollow" target="_blank"&gt;http://www.utasker.com/docs/uTasker/uTaskerADC.pdf&lt;/A&gt;&lt;SPAN&gt; for a reference to do more or less what you are doing.&lt;/SPAN&gt;&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;I have attached binary files for the &lt;STRONG&gt;Teensy 3.6&lt;/STRONG&gt; (hex file actually since the Teensy can't load binary files) and the &lt;STRONG&gt;FRDM-K66F&lt;/STRONG&gt; which sample ADC1_DM0 at 8kHz and transfer the input value to DAC0 output (both 12 bits) using PDB and DMA. It doesn't use any interrupts but can optionally trigger these at half and full buffer intervals in case the content needs to be manipulated. This reference causes a 1s delay between input and output (allowing adequate time for manipulation) but this is just the way that it is configured as reference.&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;I tested that the FRDM-K66F works correctly but, since I don't have a TEENSY-3.6, I couldn't test on the HW but the simulation was OK and I have had confirmation from Teensy 3.6 users that the generated files do (usually) run on it. I put FS USB CDC on the Teens 3.6's USB with a command line menu (in the I/O menu one can view registers with the "md" command so you can also check register content of the DMA and PDB as reference in case you can copy something).&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;As mentioned before you could get the code to do this from the uTasker open source project on GIT hub (you just need to copy some code and not use the complete environment).&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;Note that I only changed one line in the reference code for the Teensy 3.6 &lt;BR /&gt;&lt;STRONG&gt;adc_setup.int_adc_bit = ADC_DM1_SINGLE;&lt;/STRONG&gt;&lt;BR /&gt;to&lt;BR /&gt;&lt;STRONG&gt;adc_setup.int_adc_bit = ADC_DM0_SINGLE;&lt;/STRONG&gt;&lt;BR /&gt;since the K66 doesn't have an ADC1_DM1 input (as various other K parts do).&lt;BR /&gt;Otherwise I took the reference project and enabled TEST_AD_DA in ADC_Timer.h (ensuring SUPPORT_PDB, SUPPORT_DAC and SUPPORT_ADC were also enabled for the respective drivers) and build. On the HW the operation was immediately successful.&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;If you have limited time it makes sense in using more power-ful solutions that you presently use - did you receive your FRDM-K66F board yet?&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;Regards&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;P&gt;Mark&lt;/P&gt;&lt;/BODY&gt;&lt;/HTML&gt;</description>
      <pubDate>Sat, 21 Oct 2017 14:12:50 GMT</pubDate>
      <guid>https://community.nxp.com/t5/Kinetis-Microcontrollers/Audio-double-buffering-on-K66/m-p/700797#M43108</guid>
      <dc:creator>mjbcswitzerland</dc:creator>
      <dc:date>2017-10-21T14:12:50Z</dc:date>
    </item>
  </channel>
</rss>

