ADAT white noise on Teensy 4.0

alrj

Well-known member
Hello all..

I have realised that the spdif out works with T4 so I have been comparing output_spdif.cpp to output_adat.cpp and making changes trying to get it working. I have persuaded it to compile but I just get noise in the left channel at the moment with WavFilePlayer and an ADAT output.

I think the issue is that I need to set 8 words per frame here but I dont know how...

Code:
// fix..4 Words per Frame 32 Bit Word-Length -> 128 Bit Frame-Length, MSB First:
    // i want.. 8 Words per Frame 32 Bit Word-Length -> 256 Bit Frame-Length, MSB First:
	I2S1_TCR4 = I2S_TCR4_FRSZ(3) | I2S_TCR4_SYWD(0) | I2S_TCR4_MF | I2S_TCR4_FSP | I2S_TCR4_FSD;
	I2S1_TCR5 = I2S_TCR5_WNW(31) | I2S_TCR5_W0W(31) | I2S_TCR5_FBT(31);

Here is the full edited output_adat.cpp...

Code:
/* ADAT for Teensy 3.X
 * Copyright (c) 2017, Ernstjan Freriks,
 * Thanks to Frank Bösing & KPC & Paul Stoffregen!
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice, development funding notice, and this permission
 * notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include <Arduino.h>
#include "output_adat.h"
#include "utility/imxrt_hw.h"

#if defined(KINETISK) || defined(__IMXRT1052__) || defined(__IMXRT1062__) //AAA

audio_block_t * AudioOutputADAT::block_ch1_1st = NULL;
audio_block_t * AudioOutputADAT::block_ch2_1st = NULL;
audio_block_t * AudioOutputADAT::block_ch3_1st = NULL;
audio_block_t * AudioOutputADAT::block_ch4_1st = NULL;
audio_block_t * AudioOutputADAT::block_ch5_1st = NULL;
audio_block_t * AudioOutputADAT::block_ch6_1st = NULL;
audio_block_t * AudioOutputADAT::block_ch7_1st = NULL;
audio_block_t * AudioOutputADAT::block_ch8_1st = NULL;

audio_block_t * AudioOutputADAT::block_ch1_2nd = NULL;
audio_block_t * AudioOutputADAT::block_ch2_2nd = NULL;
audio_block_t * AudioOutputADAT::block_ch3_2nd = NULL;
audio_block_t * AudioOutputADAT::block_ch4_2nd = NULL;
audio_block_t * AudioOutputADAT::block_ch5_2nd = NULL;
audio_block_t * AudioOutputADAT::block_ch6_2nd = NULL;
audio_block_t * AudioOutputADAT::block_ch7_2nd = NULL;
audio_block_t * AudioOutputADAT::block_ch8_2nd = NULL;

uint16_t  AudioOutputADAT::ch1_offset = 0;
uint16_t  AudioOutputADAT::ch2_offset = 0;
uint16_t  AudioOutputADAT::ch3_offset = 0;
uint16_t  AudioOutputADAT::ch4_offset = 0;
uint16_t  AudioOutputADAT::ch5_offset = 0;
uint16_t  AudioOutputADAT::ch6_offset = 0;
uint16_t  AudioOutputADAT::ch7_offset = 0;
uint16_t  AudioOutputADAT::ch8_offset = 0;

bool AudioOutputADAT::update_responsibility = false;
//uint32_t  AudioOutputADAT::vucp = VUCP_VALID;

DMAMEM static uint32_t ADAT_tx_buffer[AUDIO_BLOCK_SAMPLES * 8]; //4 KB, AUDIO_BLOCK_SAMPLES is usually 128

DMAChannel AudioOutputADAT::dma(false);

static const uint32_t zerodata[AUDIO_BLOCK_SAMPLES/4] = {0};

// These are the lookup tables. There are four of them so that the remainder of the 32 bit result can easily be XORred with the next 8 bits.
static const uint32_t LookupTable_firstword[256]  = { 0x0, 0x1ffffff, 0x3ffffff, 0x2000000, 0x7ffffff, 0x6000000, 0x4000000, 0x5ffffff, 0xfffffff, 0xe000000, 0xc000000, 0xdffffff, 0x8000000, 0x9ffffff, 0xbffffff, 0xa000000, 0x1fffffff, 0x1e000000, 0x1c000000, 0x1dffffff, 0x18000000, 0x19ffffff, 0x1bffffff, 0x1a000000, 0x10000000, 0x11ffffff, 0x13ffffff, 0x12000000, 0x17ffffff, 0x16000000, 0x14000000, 0x15ffffff, 0x3fffffff, 0x3e000000, 0x3c000000, 0x3dffffff, 0x38000000, 0x39ffffff, 0x3bffffff, 0x3a000000, 0x30000000, 0x31ffffff, 0x33ffffff, 0x32000000, 0x37ffffff, 0x36000000, 0x34000000, 0x35ffffff, 0x20000000, 0x21ffffff, 0x23ffffff, 0x22000000, 0x27ffffff, 0x26000000, 0x24000000, 0x25ffffff, 0x2fffffff, 0x2e000000, 0x2c000000, 0x2dffffff, 0x28000000, 0x29ffffff, 0x2bffffff, 0x2a000000, 0x7fffffff, 0x7e000000, 0x7c000000, 0x7dffffff, 0x78000000, 0x79ffffff, 0x7bffffff, 0x7a000000, 0x70000000, 0x71ffffff, 0x73ffffff, 0x72000000, 0x77ffffff, 0x76000000, 0x74000000, 0x75ffffff, 0x60000000, 0x61ffffff, 0x63ffffff, 0x62000000, 0x67ffffff, 0x66000000, 0x64000000, 0x65ffffff, 0x6fffffff, 0x6e000000, 0x6c000000, 0x6dffffff, 0x68000000, 0x69ffffff, 0x6bffffff, 0x6a000000, 0x40000000, 0x41ffffff, 0x43ffffff, 0x42000000, 0x47ffffff, 0x46000000, 0x44000000, 0x45ffffff, 0x4fffffff, 0x4e000000, 0x4c000000, 0x4dffffff, 0x48000000, 0x49ffffff, 0x4bffffff, 0x4a000000, 0x5fffffff, 0x5e000000, 0x5c000000, 0x5dffffff, 0x58000000, 0x59ffffff, 0x5bffffff, 0x5a000000, 0x50000000, 0x51ffffff, 0x53ffffff, 0x52000000, 0x57ffffff, 0x56000000, 0x54000000, 0x55ffffff, 0xffffffff, 0xfe000000, 0xfc000000, 0xfdffffff, 0xf8000000, 0xf9ffffff, 0xfbffffff, 0xfa000000, 0xf0000000, 0xf1ffffff, 0xf3ffffff, 0xf2000000, 0xf7ffffff, 0xf6000000, 0xf4000000, 0xf5ffffff, 0xe0000000, 0xe1ffffff, 0xe3ffffff, 0xe2000000, 0xe7ffffff, 0xe6000000, 0xe4000000, 0xe5ffffff, 0xefffffff, 0xee000000, 0xec000000, 0xedffffff, 0xe8000000, 0xe9ffffff, 0xebffffff, 0xea000000, 0xc0000000, 0xc1ffffff, 0xc3ffffff, 0xc2000000, 0xc7ffffff, 0xc6000000, 0xc4000000, 0xc5ffffff, 0xcfffffff, 0xce000000, 0xcc000000, 0xcdffffff, 0xc8000000, 0xc9ffffff, 0xcbffffff, 0xca000000, 0xdfffffff, 0xde000000, 0xdc000000, 0xddffffff, 0xd8000000, 0xd9ffffff, 0xdbffffff, 0xda000000, 0xd0000000, 0xd1ffffff, 0xd3ffffff, 0xd2000000, 0xd7ffffff, 0xd6000000, 0xd4000000, 0xd5ffffff, 0x80000000, 0x81ffffff, 0x83ffffff, 0x82000000, 0x87ffffff, 0x86000000, 0x84000000, 0x85ffffff, 0x8fffffff, 0x8e000000, 0x8c000000, 0x8dffffff, 0x88000000, 0x89ffffff, 0x8bffffff, 0x8a000000, 0x9fffffff, 0x9e000000, 0x9c000000, 0x9dffffff, 0x98000000, 0x99ffffff, 0x9bffffff, 0x9a000000, 0x90000000, 0x91ffffff, 0x93ffffff, 0x92000000, 0x97ffffff, 0x96000000, 0x94000000, 0x95ffffff, 0xbfffffff, 0xbe000000, 0xbc000000, 0xbdffffff, 0xb8000000, 0xb9ffffff, 0xbbffffff, 0xba000000, 0xb0000000, 0xb1ffffff, 0xb3ffffff, 0xb2000000, 0xb7ffffff, 0xb6000000, 0xb4000000, 0xb5ffffff, 0xa0000000, 0xa1ffffff, 0xa3ffffff, 0xa2000000, 0xa7ffffff, 0xa6000000, 0xa4000000, 0xa5ffffff, 0xafffffff, 0xae000000, 0xac000000, 0xadffffff, 0xa8000000, 0xa9ffffff, 0xabffffff, 0xaa000000};
static const uint32_t LookupTable_secondword[256] = { 0x0, 0x1ffff, 0x3ffff, 0x20000, 0x7ffff, 0x60000, 0x40000, 0x5ffff, 0xfffff, 0xe0000, 0xc0000, 0xdffff, 0x80000, 0x9ffff, 0xbffff, 0xa0000, 0x1fffff, 0x1e0000, 0x1c0000, 0x1dffff, 0x180000, 0x19ffff, 0x1bffff, 0x1a0000, 0x100000, 0x11ffff, 0x13ffff, 0x120000, 0x17ffff, 0x160000, 0x140000, 0x15ffff, 0x3fffff, 0x3e0000, 0x3c0000, 0x3dffff, 0x380000, 0x39ffff, 0x3bffff, 0x3a0000, 0x300000, 0x31ffff, 0x33ffff, 0x320000, 0x37ffff, 0x360000, 0x340000, 0x35ffff, 0x200000, 0x21ffff, 0x23ffff, 0x220000, 0x27ffff, 0x260000, 0x240000, 0x25ffff, 0x2fffff, 0x2e0000, 0x2c0000, 0x2dffff, 0x280000, 0x29ffff, 0x2bffff, 0x2a0000, 0x7fffff, 0x7e0000, 0x7c0000, 0x7dffff, 0x780000, 0x79ffff, 0x7bffff, 0x7a0000, 0x700000, 0x71ffff, 0x73ffff, 0x720000, 0x77ffff, 0x760000, 0x740000, 0x75ffff, 0x600000, 0x61ffff, 0x63ffff, 0x620000, 0x67ffff, 0x660000, 0x640000, 0x65ffff, 0x6fffff, 0x6e0000, 0x6c0000, 0x6dffff, 0x680000, 0x69ffff, 0x6bffff, 0x6a0000, 0x400000, 0x41ffff, 0x43ffff, 0x420000, 0x47ffff, 0x460000, 0x440000, 0x45ffff, 0x4fffff, 0x4e0000, 0x4c0000, 0x4dffff, 0x480000, 0x49ffff, 0x4bffff, 0x4a0000, 0x5fffff, 0x5e0000, 0x5c0000, 0x5dffff, 0x580000, 0x59ffff, 0x5bffff, 0x5a0000, 0x500000, 0x51ffff, 0x53ffff, 0x520000, 0x57ffff, 0x560000, 0x540000, 0x55ffff, 0xffffff, 0xfe0000, 0xfc0000, 0xfdffff, 0xf80000, 0xf9ffff, 0xfbffff, 0xfa0000, 0xf00000, 0xf1ffff, 0xf3ffff, 0xf20000, 0xf7ffff, 0xf60000, 0xf40000, 0xf5ffff, 0xe00000, 0xe1ffff, 0xe3ffff, 0xe20000, 0xe7ffff, 0xe60000, 0xe40000, 0xe5ffff, 0xefffff, 0xee0000, 0xec0000, 0xedffff, 0xe80000, 0xe9ffff, 0xebffff, 0xea0000, 0xc00000, 0xc1ffff, 0xc3ffff, 0xc20000, 0xc7ffff, 0xc60000, 0xc40000, 0xc5ffff, 0xcfffff, 0xce0000, 0xcc0000, 0xcdffff, 0xc80000, 0xc9ffff, 0xcbffff, 0xca0000, 0xdfffff, 0xde0000, 0xdc0000, 0xddffff, 0xd80000, 0xd9ffff, 0xdbffff, 0xda0000, 0xd00000, 0xd1ffff, 0xd3ffff, 0xd20000, 0xd7ffff, 0xd60000, 0xd40000, 0xd5ffff, 0x800000, 0x81ffff, 0x83ffff, 0x820000, 0x87ffff, 0x860000, 0x840000, 0x85ffff, 0x8fffff, 0x8e0000, 0x8c0000, 0x8dffff, 0x880000, 0x89ffff, 0x8bffff, 0x8a0000, 0x9fffff, 0x9e0000, 0x9c0000, 0x9dffff, 0x980000, 0x99ffff, 0x9bffff, 0x9a0000, 0x900000, 0x91ffff, 0x93ffff, 0x920000, 0x97ffff, 0x960000, 0x940000, 0x95ffff, 0xbfffff, 0xbe0000, 0xbc0000, 0xbdffff, 0xb80000, 0xb9ffff, 0xbbffff, 0xba0000, 0xb00000, 0xb1ffff, 0xb3ffff, 0xb20000, 0xb7ffff, 0xb60000, 0xb40000, 0xb5ffff, 0xa00000, 0xa1ffff, 0xa3ffff, 0xa20000, 0xa7ffff, 0xa60000, 0xa40000, 0xa5ffff, 0xafffff, 0xae0000, 0xac0000, 0xadffff, 0xa80000, 0xa9ffff, 0xabffff, 0xaa0000};
static const uint32_t LookupTable_thirdword[256]  = { 0x0, 0x1ff, 0x3ff, 0x200, 0x7ff, 0x600, 0x400, 0x5ff, 0xfff, 0xe00, 0xc00, 0xdff, 0x800, 0x9ff, 0xbff, 0xa00, 0x1fff, 0x1e00, 0x1c00, 0x1dff, 0x1800, 0x19ff, 0x1bff, 0x1a00, 0x1000, 0x11ff, 0x13ff, 0x1200, 0x17ff, 0x1600, 0x1400, 0x15ff, 0x3fff, 0x3e00, 0x3c00, 0x3dff, 0x3800, 0x39ff, 0x3bff, 0x3a00, 0x3000, 0x31ff, 0x33ff, 0x3200, 0x37ff, 0x3600, 0x3400, 0x35ff, 0x2000, 0x21ff, 0x23ff, 0x2200, 0x27ff, 0x2600, 0x2400, 0x25ff, 0x2fff, 0x2e00, 0x2c00, 0x2dff, 0x2800, 0x29ff, 0x2bff, 0x2a00, 0x7fff, 0x7e00, 0x7c00, 0x7dff, 0x7800, 0x79ff, 0x7bff, 0x7a00, 0x7000, 0x71ff, 0x73ff, 0x7200, 0x77ff, 0x7600, 0x7400, 0x75ff, 0x6000, 0x61ff, 0x63ff, 0x6200, 0x67ff, 0x6600, 0x6400, 0x65ff, 0x6fff, 0x6e00, 0x6c00, 0x6dff, 0x6800, 0x69ff, 0x6bff, 0x6a00, 0x4000, 0x41ff, 0x43ff, 0x4200, 0x47ff, 0x4600, 0x4400, 0x45ff, 0x4fff, 0x4e00, 0x4c00, 0x4dff, 0x4800, 0x49ff, 0x4bff, 0x4a00, 0x5fff, 0x5e00, 0x5c00, 0x5dff, 0x5800, 0x59ff, 0x5bff, 0x5a00, 0x5000, 0x51ff, 0x53ff, 0x5200, 0x57ff, 0x5600, 0x5400, 0x55ff, 0xffff, 0xfe00, 0xfc00, 0xfdff, 0xf800, 0xf9ff, 0xfbff, 0xfa00, 0xf000, 0xf1ff, 0xf3ff, 0xf200, 0xf7ff, 0xf600, 0xf400, 0xf5ff, 0xe000, 0xe1ff, 0xe3ff, 0xe200, 0xe7ff, 0xe600, 0xe400, 0xe5ff, 0xefff, 0xee00, 0xec00, 0xedff, 0xe800, 0xe9ff, 0xebff, 0xea00, 0xc000, 0xc1ff, 0xc3ff, 0xc200, 0xc7ff, 0xc600, 0xc400, 0xc5ff, 0xcfff, 0xce00, 0xcc00, 0xcdff, 0xc800, 0xc9ff, 0xcbff, 0xca00, 0xdfff, 0xde00, 0xdc00, 0xddff, 0xd800, 0xd9ff, 0xdbff, 0xda00, 0xd000, 0xd1ff, 0xd3ff, 0xd200, 0xd7ff, 0xd600, 0xd400, 0xd5ff, 0x8000, 0x81ff, 0x83ff, 0x8200, 0x87ff, 0x8600, 0x8400, 0x85ff, 0x8fff, 0x8e00, 0x8c00, 0x8dff, 0x8800, 0x89ff, 0x8bff, 0x8a00, 0x9fff, 0x9e00, 0x9c00, 0x9dff, 0x9800, 0x99ff, 0x9bff, 0x9a00, 0x9000, 0x91ff, 0x93ff, 0x9200, 0x97ff, 0x9600, 0x9400, 0x95ff, 0xbfff, 0xbe00, 0xbc00, 0xbdff, 0xb800, 0xb9ff, 0xbbff, 0xba00, 0xb000, 0xb1ff, 0xb3ff, 0xb200, 0xb7ff, 0xb600, 0xb400, 0xb5ff, 0xa000, 0xa1ff, 0xa3ff, 0xa200, 0xa7ff, 0xa600, 0xa400, 0xa5ff, 0xafff, 0xae00, 0xac00, 0xadff, 0xa800, 0xa9ff, 0xabff, 0xaa00};
static const uint32_t LookupTable_fourthword[256] = { 0x0, 0x1, 0x3, 0x2, 0x7, 0x6, 0x4, 0x5, 0xf, 0xe, 0xc, 0xd, 0x8, 0x9, 0xb, 0xa, 0x1f, 0x1e, 0x1c, 0x1d, 0x18, 0x19, 0x1b, 0x1a, 0x10, 0x11, 0x13, 0x12, 0x17, 0x16, 0x14, 0x15, 0x3f, 0x3e, 0x3c, 0x3d, 0x38, 0x39, 0x3b, 0x3a, 0x30, 0x31, 0x33, 0x32, 0x37, 0x36, 0x34, 0x35, 0x20, 0x21, 0x23, 0x22, 0x27, 0x26, 0x24, 0x25, 0x2f, 0x2e, 0x2c, 0x2d, 0x28, 0x29, 0x2b, 0x2a, 0x7f, 0x7e, 0x7c, 0x7d, 0x78, 0x79, 0x7b, 0x7a, 0x70, 0x71, 0x73, 0x72, 0x77, 0x76, 0x74, 0x75, 0x60, 0x61, 0x63, 0x62, 0x67, 0x66, 0x64, 0x65, 0x6f, 0x6e, 0x6c, 0x6d, 0x68, 0x69, 0x6b, 0x6a, 0x40, 0x41, 0x43, 0x42, 0x47, 0x46, 0x44, 0x45, 0x4f, 0x4e, 0x4c, 0x4d, 0x48, 0x49, 0x4b, 0x4a, 0x5f, 0x5e, 0x5c, 0x5d, 0x58, 0x59, 0x5b, 0x5a, 0x50, 0x51, 0x53, 0x52, 0x57, 0x56, 0x54, 0x55, 0xff, 0xfe, 0xfc, 0xfd, 0xf8, 0xf9, 0xfb, 0xfa, 0xf0, 0xf1, 0xf3, 0xf2, 0xf7, 0xf6, 0xf4, 0xf5, 0xe0, 0xe1, 0xe3, 0xe2, 0xe7, 0xe6, 0xe4, 0xe5, 0xef, 0xee, 0xec, 0xed, 0xe8, 0xe9, 0xeb, 0xea, 0xc0, 0xc1, 0xc3, 0xc2, 0xc7, 0xc6, 0xc4, 0xc5, 0xcf, 0xce, 0xcc, 0xcd, 0xc8, 0xc9, 0xcb, 0xca, 0xdf, 0xde, 0xdc, 0xdd, 0xd8, 0xd9, 0xdb, 0xda, 0xd0, 0xd1, 0xd3, 0xd2, 0xd7, 0xd6, 0xd4, 0xd5, 0x80, 0x81, 0x83, 0x82, 0x87, 0x86, 0x84, 0x85, 0x8f, 0x8e, 0x8c, 0x8d, 0x88, 0x89, 0x8b, 0x8a, 0x9f, 0x9e, 0x9c, 0x9d, 0x98, 0x99, 0x9b, 0x9a, 0x90, 0x91, 0x93, 0x92, 0x97, 0x96, 0x94, 0x95, 0xbf, 0xbe, 0xbc, 0xbd, 0xb8, 0xb9, 0xbb, 0xba, 0xb0, 0xb1, 0xb3, 0xb2, 0xb7, 0xb6, 0xb4, 0xb5, 0xa0, 0xa1, 0xa3, 0xa2, 0xa7, 0xa6, 0xa4, 0xa5, 0xaf, 0xae, 0xac, 0xad, 0xa8, 0xa9, 0xab, 0xaa};

void AudioOutputADAT::begin(void)
{

	dma.begin(true); // Allocate the DMA channel first

	block_ch1_1st = NULL;
	block_ch2_1st = NULL;
	block_ch3_1st = NULL;
	block_ch4_1st = NULL;
	block_ch5_1st = NULL;
	block_ch6_1st = NULL;
	block_ch7_1st = NULL;
	block_ch8_1st = NULL;

	// TODO: should we set & clear the I2S_TCSR_SR bit here?
	config_ADAT();
#if defined(KINETISK)
	CORE_PIN22_CONFIG = PORT_PCR_MUX(6); // pin 22, PTC1, I2S0_TXD0

	const int nbytes_mlno = 2 * 8; // 16 Bytes per minor loop

	dma.TCD->SADDR = ADAT_tx_buffer;
	dma.TCD->SOFF = 4;
	dma.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); //transfersize 2 = 32 bit, 5 = 32 byte
	dma.TCD->NBYTES_MLNO = nbytes_mlno;
	dma.TCD->SLAST = -sizeof(ADAT_tx_buffer);
	dma.TCD->DADDR = &I2S0_TDR0;
	dma.TCD->DOFF = 0;
	dma.TCD->CITER_ELINKNO = sizeof(ADAT_tx_buffer) / nbytes_mlno;
	dma.TCD->DLASTSGA = 0;
	dma.TCD->BITER_ELINKNO = sizeof(ADAT_tx_buffer) / nbytes_mlno;
	dma.TCD->CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR;
	dma.triggerAtHardwareEvent(DMAMUX_SOURCE_I2S0_TX);
	update_responsibility = update_setup();
	dma.enable();

	I2S0_TCSR |= I2S_TCSR_TE | I2S_TCSR_BCE | I2S_TCSR_FRDE | I2S_TCSR_FR;
	dma.attachInterrupt(isr);
#elif defined(__IMXRT1052__) || defined(__IMXRT1062__)

#if defined(__IMXRT1052__)
	CORE_PIN6_CONFIG  = 3;  //1:TX_DATA0
#elif defined(__IMXRT1062__)
	CORE_PIN7_CONFIG  = 3;  //1:TX_DATA0	
#endif		
	
	const int nbytes_mlno = 2 * 8; // 16 Bytes per minor loop

	dma.TCD->SADDR = ADAT_tx_buffer;
	dma.TCD->SOFF = 4;
	dma.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2);
	dma.TCD->NBYTES_MLNO = nbytes_mlno;
	dma.TCD->SLAST = -sizeof(ADAT_tx_buffer);
	dma.TCD->DADDR = &I2S1_TDR0;
	dma.TCD->DOFF = 0;
	dma.TCD->CITER_ELINKNO = sizeof(ADAT_tx_buffer) / nbytes_mlno;
	dma.TCD->DLASTSGA = 0;
	dma.TCD->BITER_ELINKNO = sizeof(ADAT_tx_buffer) / nbytes_mlno;
	dma.TCD->CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR;
	dma.triggerAtHardwareEvent(DMAMUX_SOURCE_SAI1_TX);
	update_responsibility = update_setup();
	dma.enable();

	I2S1_RCSR |= I2S_RCSR_RE;
	I2S1_TCSR |= I2S_TCSR_TE | I2S_TCSR_BCE | I2S_TCSR_FRDE | I2S_TCSR_FR;
	dma.attachInterrupt(isr);
#endif
}


/*

	https://ackspace.nl/wiki/ADAT_project
	https://github.com/xcore/sc_adat/blob/master/module_adat_tx/src/adat_tx_port.xc

	for information about the clock:

	http://cache.freescale.com/files/32bit/doc/app_note/AN4800.pdf

	We need a bitrate twice as high as the SPDIF example.
	Because BITCLK can not be the same as MCLK, but only half of MCLK, we need a 2*MCLK (so for 44100 samplerate we need 88200 MCLK)
*/

void AudioOutputADAT::isr(void)
{
	const int16_t *src1, *src2, *src3, *src4,*src5, *src6, *src7, *src8;
	const int16_t *zeros = (const int16_t *)zerodata;

	uint32_t *end, *dest;
	uint32_t saddr;
	uint32_t sample1, sample2, sample3, sample4, sample5, sample6, sample7, sample8;

	static uint32_t previousnrzi_highlow = 0; //this is used for the NZRI encoding to remember the last state.
	// if the result of the lookup table LSB is other than this lastbit, the result of the lookup table must be inverted.

	//static bool previousframeinverted=false;

	saddr = (uint32_t)(dma.TCD->SADDR);
	dma.clearInterrupt();
	if (saddr < (uint32_t)ADAT_tx_buffer + sizeof(ADAT_tx_buffer) / 2) {
		// DMA is transmitting the first half of the buffer
		// so we must fill the second half
		dest = (uint32_t *)&ADAT_tx_buffer[AUDIO_BLOCK_SAMPLES * 8/2];
		end = (uint32_t *)&ADAT_tx_buffer[AUDIO_BLOCK_SAMPLES * 8];
		if (AudioOutputADAT::update_responsibility) AudioStream::update_all();
	} else {
		// DMA is transmitting the second half of the buffer
		// so we must fill the first half
		dest = (uint32_t *)ADAT_tx_buffer;
		end = (uint32_t *)&ADAT_tx_buffer[AUDIO_BLOCK_SAMPLES * 8/2];
	}

	src1 = (block_ch1_1st) ? block_ch1_1st->data + ch1_offset : zeros;
	src2 = (block_ch2_1st) ? block_ch2_1st->data + ch2_offset : zeros;
	src3 = (block_ch3_1st) ? block_ch3_1st->data + ch3_offset : zeros;
	src4 = (block_ch4_1st) ? block_ch4_1st->data + ch4_offset : zeros;
	src5 = (block_ch5_1st) ? block_ch5_1st->data + ch5_offset : zeros;
	src6 = (block_ch6_1st) ? block_ch6_1st->data + ch6_offset : zeros;
	src7 = (block_ch7_1st) ? block_ch7_1st->data + ch7_offset : zeros;
	src8 = (block_ch8_1st) ? block_ch8_1st->data + ch8_offset : zeros;


	//Non-NZRI encoded 'empty' ADAT Frame
	/*     
	*(dest+0) = 0b10000100001000010000100001000010; // bit 0-31
	*(dest+1) = 0b00010000100001000010000100001000; // bit 32-63
	*(dest+2) = 0b01000010000100001000010000100001; // bit 64-95
	*(dest+3) = 0b00001000010000100001000010000100; // bit 96-127

	*(dest+4) = 0b00100001000010000100001000010000; // bit 128-159
	*(dest+5) = 0b10000100001000010000100001000010; // bit 160-191
	*(dest+6) = 0b00010000100001000010000100001000; // bit 192-223
	*(dest+7) = 0b01000010000100001000000000010000; // bit 224-255

	dest+=8;

	*/

	/*
	//NZRI encoded 'empty' ADAT Frame

	*(dest+0) = 0b11111000001111100000111110000011; // bit 0-31
	*(dest+1) = 0b11100000111110000011111000001111; // bit 32-63
	*(dest+2) = 0b10000011111000001111100000111110; // bit 64-95
	*(dest+3) = 0b00001111100000111110000011111000; // bit 96-127

	*(dest+4) = 0b00111110000011111000001111100000; // bit 128-159
	*(dest+5) = 0b11111000001111100000111110000011; // bit 160-191
	*(dest+6) = 0b11100000111110000011111000001111; // bit 192-223
	*(dest+7) = 0b10000011111000001111111111100000; // bit 224-255

	dest+=8;

	*/

	do
	{
		sample1 = (*src1++);
		sample2 = (*src2++);
		sample3 = (*src3++);
		sample4 = (*src4++);
		sample5 = (*src5++);
		sample6 = (*src6++);
		sample7 = (*src7++);
		sample8 = (*src8++);

		uint32_t value;
		uint32_t nzrivalue;

		value=				 0b10000100001000010000100001000010 /* bit  0-31 */ 
//							  b00000000000000001000000000000000 // start of 16 bit sample
			| ((sample1<<15)&0b01111000000000000000000000000000) 
			| ((sample1<<14)&0b00000011110000000000000000000000) 
			| ((sample1<<13)&0b00000000000111100000000000000000)   
			| ((sample1<<12)&0b00000000000000001111000000000000) 
			| ((sample2>>15)&0b00000000000000000000000000000001)
			; 
		nzrivalue = previousnrzi_highlow ^ (LookupTable_firstword[(byte)(value >> 24)] ^ LookupTable_secondword[(byte)(value >> 16)] ^ LookupTable_thirdword[(byte)(value >> 8)] ^ LookupTable_fourthword[(byte)value]);
		*(dest+0) = nzrivalue;
        previousnrzi_highlow = ((nzrivalue & 0b1) == 0b1) ? ~0U : 0U;
		
		value =				 0b00010000100001000010000100001000 /* bit 32-63 */ 
//							  b00000000000000001000100010001000 // start of 16 bit sample
			| ((sample2<<17)&0b11100000000000000000000000000000) 
			| ((sample2<<16)&0b00001111000000000000000000000000) 
			| ((sample2<<15)&0b00000000011110000000000000000000)   
			| ((sample2<<14)&0b00000000000000111100000000000000) 
			| ((sample3>>13)&0b00000000000000000000000000000111)
			; 
		nzrivalue = previousnrzi_highlow ^ (LookupTable_firstword[(byte)(value >> 24)] ^ LookupTable_secondword[(byte)(value >> 16)] ^ LookupTable_thirdword[(byte)(value >> 8)] ^ LookupTable_fourthword[(byte)value]);
		*(dest+1) = nzrivalue;
        previousnrzi_highlow = ((nzrivalue & 0b1) == 0b1) ? ~0U : 0U;


		value =				 0b01000010000100001000010000100001 /* bit 64-95 */ 
//							  b00000000000000001000000000000000 // start of 16 bit sample
			| ((sample3<<19)&0b10000000000000000000000000000000) 
			| ((sample3<<18)&0b00111100000000000000000000000000)  
			| ((sample3<<17)&0b00000001111000000000000000000000)  
			| ((sample3<<16)&0b00000000000011110000000000000000) 
			| ((sample4>>11)&0b00000000000000000000000000011110)
			;
		nzrivalue = previousnrzi_highlow ^ (LookupTable_firstword[(byte)(value >> 24)] ^ LookupTable_secondword[(byte)(value >> 16)] ^ LookupTable_thirdword[(byte)(value >> 8)] ^ LookupTable_fourthword[(byte)value]);
		*(dest+2) = nzrivalue;
        previousnrzi_highlow = ((nzrivalue & 0b1) == 0b1) ? ~0U : 0U;

		value =				 0b00001000010000100001000010000100 /* bit 96-127 */ 
//							  b00000000000000001000100010001000 // start of 16 bit sample
			| ((sample4<<20)&0b11110000000000000000000000000000) 
			| ((sample4<<19)&0b00000111100000000000000000000000) 
			| ((sample4<<18)&0b00000000001111000000000000000000) 
			| ((sample5>>9 )&0b00000000000000000000000001111000) 
			| ((sample5>>10)&0b00000000000000000000000000000011) 
			;
		nzrivalue = previousnrzi_highlow ^ (LookupTable_firstword[(byte)(value >> 24)] ^ LookupTable_secondword[(byte)(value >> 16)] ^ LookupTable_thirdword[(byte)(value >> 8)] ^ LookupTable_fourthword[(byte)value]);
		*(dest+3) = nzrivalue;
        previousnrzi_highlow = ((nzrivalue & 0b1) == 0b1) ? ~0U : 0U;

		value =				 0b00100001000010000100001000010000 /* bit 128-159 */ 
//							  b00000000000000001000100010001000 // start of 16 bit sample
			| ((sample5<<22)&0b11000000000000000000000000000000) 
			| ((sample5<<21)&0b00011110000000000000000000000000) 
			| ((sample5<<20)&0b00000000111100000000000000000000) 
			| ((sample6>>7 )&0b00000000000000000000000111100000) 
			| ((sample6>>8 )&0b00000000000000000000000000001111) 
			;
		nzrivalue = previousnrzi_highlow ^ (LookupTable_firstword[(byte)(value >> 24)] ^ LookupTable_secondword[(byte)(value >> 16)] ^ LookupTable_thirdword[(byte)(value >> 8)] ^ LookupTable_fourthword[(byte)value]);
		*(dest+4) = nzrivalue;
        previousnrzi_highlow = ((nzrivalue & 0b1) == 0b1) ? ~0U : 0U;

		value =				 0b10000100001000010000100001000010 /* bit 160-191 */
//							  b00000000000000001000100010001000 // start of 16 bit sample
			| ((sample6<<23)&0b01111000000000000000000000000000) 
			| ((sample6<<22)&0b00000011110000000000000000000000) 
			| ((sample7>>5 )&0b00000000000000000000011110000000) 
			| ((sample7>>6 )&0b00000000000000000000000000111100) 
			| ((sample7>>7 )&0b00000000000000000000000000000001) 
			;

		nzrivalue = previousnrzi_highlow ^ (LookupTable_firstword[(byte)(value >> 24)] ^ LookupTable_secondword[(byte)(value >> 16)] ^ LookupTable_thirdword[(byte)(value >> 8)] ^ LookupTable_fourthword[(byte)value]);
		*(dest+5) = nzrivalue;
        previousnrzi_highlow = ((nzrivalue & 0b1) == 0b1) ? ~0U : 0U;

		value =				 0b00010000100001000010000100001000 /* bit 192-223 */
//							  b00000000000000001000100010001000 // start of 16 bit sample
			| ((sample7<<25)&0b11100000000000000000000000000000) 
			| ((sample7<<24)&0b00001111000000000000000000000000) 
			| ((sample8>>3 )&0b00000000000000000001111000000000) 
			| ((sample8>>4 )&0b00000000000000000000000011110000) 
			| ((sample8>>5 )&0b00000000000000000000000000000111)
			;

		nzrivalue = previousnrzi_highlow ^ (LookupTable_firstword[(byte)(value >> 24)] ^ LookupTable_secondword[(byte)(value >> 16)] ^ LookupTable_thirdword[(byte)(value >> 8)] ^ LookupTable_fourthword[(byte)value]);
		*(dest+6) = nzrivalue;
        previousnrzi_highlow = ((nzrivalue & 0b1) == 0b1) ? ~0U : 0U;

		value =				 0b01000010000100001000000000010000 /* bit 224-255 */
//							  b00000000000000001000100010001000 // start of 16 bit sample
			| ((sample8<<27)&0b10000000000000000000000000000000) 
			| ((sample8<<26)&0b00111100000000000000000000000000) 
			;

		nzrivalue = previousnrzi_highlow ^ (LookupTable_firstword[(byte)(value >> 24)] ^ LookupTable_secondword[(byte)(value >> 16)] ^ LookupTable_thirdword[(byte)(value >> 8)] ^ LookupTable_fourthword[(byte)value]);
		*(dest+7) = nzrivalue;
        previousnrzi_highlow = ((nzrivalue & 0b1) == 0b1) ? ~0U : 0U;

		dest+=8;
	} while (dest < end);
	/*
	block = AudioOutputADAT::block_ch1_1st;
	if (block) {
		offset = AudioOutputADAT::ch1_offset;
		src = &block->data[offset];
		do {

			sample = (uint32_t)*src++;

		} while (dest < end);
		offset += AUDIO_BLOCK_SAMPLES/2;
		if (offset < AUDIO_BLOCK_SAMPLES) {
			AudioOutputADAT::ch1_offset = offset;
		} else {
			AudioOutputADAT::ch1_offset = 0;
			AudioStream::release(block);
			AudioOutputADAT::block_ch1_1st = AudioOutputADAT::block_ch1_2nd;
			AudioOutputADAT::block_ch1_2nd = NULL;
		}
	} else {
		sample = 0;
	
		do {
			// *(dest+0) = 0b11111000001111100000111110000011; // bit 0-31
			// *(dest+1) = 0b11100000111110000011111000001111; // bit 32-63
			// *(dest+2) = 0b10000011111000001111100000111110; // bit 64-95
			// *(dest+3) = 0b00001111100000111110000011111000; // bit 96-127

			// *(dest+4) = 0b00111110000011111000001111100000; // bit 128-159
			// *(dest+5) = 0b11111000001111100000111110000011; // bit 160-191
			// *(dest+6) = 0b11100000111110000011111000001111; // bit 192-223
			// *(dest+7) = 0b10000011111000001111111111100000; // bit 224-255
			dest+=8;
		} while (dest < end);
	}

	
	dest -= AUDIO_BLOCK_SAMPLES * 8/2 - 8/2;
	block = AudioOutputADAT::block_ch2_1st;
	if (block) {
		offset = AudioOutputADAT::ch2_offset;
		src = &block->data[offset];

		do {
			sample = *src++;
			
			// *(dest+0) = 0b00111110000011111000001111100000; // bit 128-159
			// *(dest+1) = 0b11111000001111100000111110000011; // bit 160-191
			// *(dest+2) = 0b11100000111110000011111000001111; // bit 192-223
			// *(dest+3) = 0b10000011111000001111111111100000; // bit 224-255
			dest+=8;
		} while (dest < end);

		offset += AUDIO_BLOCK_SAMPLES/2;
		if (offset < AUDIO_BLOCK_SAMPLES) {
			AudioOutputADAT::ch2_offset = offset;
		} else {
			AudioOutputADAT::ch2_offset = 0;
			AudioStream::release(block);
			AudioOutputADAT::block_ch2_1st = AudioOutputADAT::block_ch2_2nd;
			AudioOutputADAT::block_ch2_2nd = NULL;
		}
	} else {
			// *(dest+0) = 0b00111110000011111000001111100000; // bit 128-159
			// *(dest+1) = 0b11111000001111100000111110000011; // bit 160-191
			// *(dest+2) = 0b11100000111110000011111000001111; // bit 192-223
			// *(dest+3) = 0b10000011111000001111111111100000; // bit 224-255
			dest+=8;
	}*/

	if (block_ch1_1st) {
		if (ch1_offset == 0) {
			ch1_offset = AUDIO_BLOCK_SAMPLES/2;
		} else {
			ch1_offset = 0;
			release(block_ch1_1st);
			block_ch1_1st = block_ch1_2nd;
			block_ch1_2nd = NULL;
		}
	}
	if (block_ch2_1st) {
		if (ch2_offset == 0) {
			ch2_offset = AUDIO_BLOCK_SAMPLES/2;
		} else {
			ch2_offset = 0;
			release(block_ch2_1st);
			block_ch2_1st = block_ch2_2nd;
			block_ch2_2nd = NULL;
		}
	}
	if (block_ch3_1st) {
		if (ch3_offset == 0) {
			ch3_offset = AUDIO_BLOCK_SAMPLES/2;
		} else {
			ch3_offset = 0;
			release(block_ch3_1st);
			block_ch3_1st = block_ch3_2nd;
			block_ch3_2nd = NULL;
		}
	}
	if (block_ch4_1st) {
		if (ch4_offset == 0) {
			ch4_offset = AUDIO_BLOCK_SAMPLES/2;
		} else {
			ch4_offset = 0;
			release(block_ch4_1st);
			block_ch4_1st = block_ch4_2nd;
			block_ch4_2nd = NULL;
		}
	}
	if (block_ch5_1st) {
		if (ch5_offset == 0) {
			ch5_offset = AUDIO_BLOCK_SAMPLES/2;
		} else {
			ch5_offset = 0;
			release(block_ch5_1st);
			block_ch5_1st = block_ch5_2nd;
			block_ch5_2nd = NULL;
		}
	}
	if (block_ch6_1st) {
		if (ch6_offset == 0) {
			ch6_offset = AUDIO_BLOCK_SAMPLES/2;
		} else {
			ch6_offset = 0;
			release(block_ch6_1st);
			block_ch6_1st = block_ch6_2nd;
			block_ch6_2nd = NULL;
		}
	}
	if (block_ch7_1st) {
		if (ch7_offset == 0) {
			ch7_offset = AUDIO_BLOCK_SAMPLES/2;
		} else {
			ch7_offset = 0;
			release(block_ch7_1st);
			block_ch7_1st = block_ch7_2nd;
			block_ch7_2nd = NULL;
		}
	}
	if (block_ch8_1st) {
		if (ch8_offset == 0) {
			ch8_offset = AUDIO_BLOCK_SAMPLES/2;
		} else {
			ch8_offset = 0;
			release(block_ch8_1st);
			block_ch8_1st = block_ch8_2nd;
			block_ch8_2nd = NULL;
		}
	}
}

void AudioOutputADAT::mute_PCM(const bool mute)
{
	//vucp = mute?VUCP_INVALID:VUCP_VALID;
	//#TODO
}

void AudioOutputADAT::update(void)
{

	audio_block_t *block, *tmp;

	block = receiveReadOnly(0); // input 0 = channel 1
	if (block) {
		__disable_irq();
		if (block_ch1_1st == NULL) {
			block_ch1_1st = block;
			ch1_offset = 0;
			__enable_irq();
		} else if (block_ch1_2nd == NULL) {
			block_ch1_2nd = block;
			__enable_irq();
		} else {
			tmp = block_ch1_1st;
			block_ch1_1st = block_ch1_2nd;
			block_ch1_2nd = block;
			ch1_offset = 0;
			__enable_irq();
			release(tmp);
		}
	}
	block = receiveReadOnly(1); // input 1 = channel 2
	if (block) {
		__disable_irq();
		if (block_ch2_1st == NULL) {
			block_ch2_1st = block;
			ch2_offset = 0;
			__enable_irq();
		} else if (block_ch2_2nd == NULL) {
			block_ch2_2nd = block;
			__enable_irq();
		} else {
			tmp = block_ch2_1st;
			block_ch2_1st = block_ch2_2nd;
			block_ch2_2nd = block;
			ch2_offset = 0;
			__enable_irq();
			release(tmp);
		}
	}
	block = receiveReadOnly(2); // channel 3
	if (block) {
		__disable_irq();
		if (block_ch3_1st == NULL) {
			block_ch3_1st = block;
			ch3_offset = 0;
			__enable_irq();
		} else if (block_ch3_2nd == NULL) {
			block_ch3_2nd = block;
			__enable_irq();
		} else {
			tmp = block_ch3_1st;
			block_ch3_1st = block_ch3_2nd;
			block_ch3_2nd = block;
			ch3_offset = 0;
			__enable_irq();
			release(tmp);
		}
	}
	block = receiveReadOnly(3); // channel 4
	if (block) {
		__disable_irq();
		if (block_ch4_1st == NULL) {
			block_ch4_1st = block;
			ch4_offset = 0;
			__enable_irq();
		} else if (block_ch4_2nd == NULL) {
			block_ch4_2nd = block;
			__enable_irq();
		} else {
			tmp = block_ch4_1st;
			block_ch4_1st = block_ch4_2nd;
			block_ch4_2nd = block;
			ch4_offset = 0;
			__enable_irq();
			release(tmp);
		}
	}
	block = receiveReadOnly(4); // channel 5
	if (block) {
		__disable_irq();
		if (block_ch5_1st == NULL) {
			block_ch5_1st = block;
			ch5_offset = 0;
			__enable_irq();
		} else if (block_ch5_2nd == NULL) {
			block_ch5_2nd = block;
			__enable_irq();
		} else {
			tmp = block_ch5_1st;
			block_ch5_1st = block_ch5_2nd;
			block_ch5_2nd = block;
			ch5_offset = 0;
			__enable_irq();
			release(tmp);
		}
	}
	block = receiveReadOnly(5); // channel 6
	if (block) {
		__disable_irq();
		if (block_ch6_1st == NULL) {
			block_ch6_1st = block;
			ch6_offset = 0;
			__enable_irq();
		} else if (block_ch6_2nd == NULL) {
			block_ch6_2nd = block;
			__enable_irq();
		} else {
			tmp = block_ch6_1st;
			block_ch6_1st = block_ch6_2nd;
			block_ch6_2nd = block;
			ch6_offset = 0;
			__enable_irq();
			release(tmp);
		}
	}
	block = receiveReadOnly(6); // channel 7
	if (block) {
		__disable_irq();
		if (block_ch7_1st == NULL) {
			block_ch7_1st = block;
			ch7_offset = 0;
			__enable_irq();
		} else if (block_ch7_2nd == NULL) {
			block_ch7_2nd = block;
			__enable_irq();
		} else {
			tmp = block_ch7_1st;
			block_ch7_1st = block_ch7_2nd;
			block_ch7_2nd = block;
			ch7_offset = 0;
			__enable_irq();
			release(tmp);
		}
	}
	block = receiveReadOnly(7); // channel 8
	if (block) {
		__disable_irq();
		if (block_ch8_1st == NULL) {
			block_ch8_1st = block;
			ch8_offset = 0;
			__enable_irq();
		} else if (block_ch8_2nd == NULL) {
			block_ch8_2nd = block;
			__enable_irq();
		} else {
			tmp = block_ch8_1st;
			block_ch8_1st = block_ch8_2nd;
			block_ch8_2nd = block;
			ch8_offset = 0;
			__enable_irq();
			release(tmp);
		}
	}
}


#ifndef MCLK_SRC
#if F_CPU >= 20000000
  #define MCLK_SRC  3  // the PLL
#else
  #define MCLK_SRC  0  // system clock
#endif
#endif


void AudioOutputADAT::config_ADAT(void)
{
#if defined(KINETISK)
	SIM_SCGC6 |= SIM_SCGC6_I2S;
	SIM_SCGC7 |= SIM_SCGC7_DMA;
	SIM_SCGC6 |= SIM_SCGC6_DMAMUX;

	// enable MCLK output
	I2S0_MCR = I2S_MCR_MICS(MCLK_SRC) | I2S_MCR_MOE;
	while (I2S0_MCR & I2S_MCR_DUF) ;
	I2S0_MDR = I2S_MDR_FRACT((MCLK_MULT-1)) | I2S_MDR_DIVIDE((MCLK_DIV-1));

	// configure transmitter
	I2S0_TMR = 0;
	I2S0_TCR1 = I2S_TCR1_TFW(1);  // watermark
	I2S0_TCR2 = I2S_TCR2_SYNC(0) | I2S_TCR2_MSEL(1) | I2S_TCR2_BCD | I2S_TCR2_DIV(0);
	I2S0_TCR3 = I2S_TCR3_TCE;

	//8 Words per Frame 32 Bit Word-Length -> 256 Bit Frame-Length, MSB First:
	I2S0_TCR4 = I2S_TCR4_FRSZ(7) | I2S_TCR4_SYWD(0) | I2S_TCR4_MF | I2S_TCR4_FSP | I2S_TCR4_FSD;
	I2S0_TCR5 = I2S_TCR5_WNW(31) | I2S_TCR5_W0W(31) | I2S_TCR5_FBT(31);

	I2S0_RCSR = 0;

#if 0
	// configure pin mux for 3 clock signals (debug only)
	CORE_PIN23_CONFIG = PORT_PCR_MUX(6); // pin 23, PTC2, I2S0_TX_FS (LRCLK)	44.1kHz
	CORE_PIN9_CONFIG  = PORT_PCR_MUX(6); // pin  9, PTC3, I2S0_TX_BCLK		5.6 MHz
	//CORE_PIN11_CONFIG = PORT_PCR_MUX(6); // pin 11, PTC6, I2S0_MCLK			11.43MHz
#endif

#elif defined(__IMXRT1052__) || defined(__IMXRT1062__)

	CCM_CCGR5 |= CCM_CCGR5_SAI1(CCM_CCGR_ON);
//PLL:
	int fs = AUDIO_SAMPLE_RATE_EXACT;
	// PLL between 27*24 = 648MHz und 54*24=1296MHz
	int n1 = 4; //SAI prescaler 4 => (n1*n2) = multiple of 4
	int n2 = 1 + (24000000 * 27) / (fs * 256 * n1);

	double C = ((double)fs * 256 * n1 * n2) / 24000000;
	int c0 = C;
	int c2 = 10000;
	int c1 = C * c2 - (c0 * c2);
	set_audioClock(c0, c1, c2);

	CCM_CSCMR1 = (CCM_CSCMR1 & ~(CCM_CSCMR1_SAI1_CLK_SEL_MASK))
		   | CCM_CSCMR1_SAI1_CLK_SEL(2); // &0x03 // (0,1,2): PLL3PFD0, PLL5, PLL4
	CCM_CS1CDR = (CCM_CS1CDR & ~(CCM_CS1CDR_SAI1_CLK_PRED_MASK | CCM_CS1CDR_SAI1_CLK_PODF_MASK))
		   | CCM_CS1CDR_SAI1_CLK_PRED(n1-1) // &0x07
		   | CCM_CS1CDR_SAI1_CLK_PODF(n2-1); // &0x3f

	IOMUXC_GPR_GPR1 = (IOMUXC_GPR_GPR1 & ~(IOMUXC_GPR_GPR1_SAI1_MCLK1_SEL_MASK))
			| (IOMUXC_GPR_GPR1_SAI1_MCLK_DIR | IOMUXC_GPR_GPR1_SAI1_MCLK1_SEL(0));	//Select MCLK

	int rsync = 0;
	int tsync = 1;
	// configure transmitter
	I2S1_TMR = 0;
	I2S1_TCR1 = I2S_TCR1_RFW(0);  // watermark
	I2S1_TCR2 = I2S_TCR2_SYNC(tsync) | I2S_TCR2_MSEL(1) | I2S_TCR2_BCD | I2S_TCR2_DIV(0);
	I2S1_TCR3 = I2S_TCR3_TCE;

	// fix..4 Words per Frame 32 Bit Word-Length -> 128 Bit Frame-Length, MSB First:
    // i want.. 8 Words per Frame 32 Bit Word-Length -> 256 Bit Frame-Length, MSB First:
	I2S1_TCR4 = I2S_TCR4_FRSZ(3) | I2S_TCR4_SYWD(0) | I2S_TCR4_MF | I2S_TCR4_FSP | I2S_TCR4_FSD;
	I2S1_TCR5 = I2S_TCR5_WNW(31) | I2S_TCR5_W0W(31) | I2S_TCR5_FBT(31);

	//I2S1_RCSR = 0;
	I2S1_RMR = 0;
	//I2S1_RCSR = (1<<25); //Reset
	I2S1_RCR1 = I2S_RCR1_RFW(0);
	I2S1_RCR2 = I2S_RCR2_SYNC(rsync) | I2S_TCR2_MSEL(1) | I2S_TCR2_BCD | I2S_TCR2_DIV(0);
	I2S1_RCR3 = I2S_RCR3_RCE;
	I2S1_RCR4 = I2S_TCR4_FRSZ(3) | I2S_TCR4_SYWD(0) | I2S_TCR4_MF | I2S_TCR4_FSP | I2S_TCR4_FSD;
	I2S1_RCR5 = I2S_TCR5_WNW(31) | I2S_TCR5_W0W(31) | I2S_TCR5_FBT(31);

#if 0
	//debug only:
	CORE_PIN23_CONFIG = 3;  //1:MCLK	11.43MHz
	CORE_PIN21_CONFIG = 3;  //1:RX_BCLK	5.6 MHz
	CORE_PIN20_CONFIG = 3;  //1:RX_SYNC	44.1 KHz
//	CORE_PIN6_CONFIG  = 3;  //1:TX_DATA0
//	CORE_PIN7_CONFIG  = 3;  //1:RX_DATA0
#endif

#endif
}

/*

https://forum.pjrc.com/threads/38753-Discussion-about-a-simple-way-to-change-the-sample-rate

*/
/*#if defined(KINETISK) //AAA this needs attentuion as im sure it will break KINETISK

void AudioOutputADAT::setI2SFreq(int freq) {
  typedef struct {
    uint8_t mult;
    uint16_t div;
  } tmclk;

  const int numfreqs = 14;
  const int samplefreqs[numfreqs] = { 8000, 11025, 16000, 22050, 32000, 44100, (int) 44117.64706 , 48000, 88200, (int) (44117.64706 * 2.0), 96000, 176400,(int) (44117.64706 * 4.0), 192000};

#if (F_PLL==16000000)
  const tmclk clkArr[numfreqs] = {{16, 125}, {148, 839}, {32, 125}, {145, 411}, {64, 125}, {151, 214}, {12, 17}, {96, 125}, {151, 107}, {24, 17}, {192, 125}, {127, 45}, {48, 17}, {255, 83} };
#elif (F_PLL==72000000)
  const tmclk clkArr[numfreqs] = {{32, 1125}, {49, 1250}, {64, 1125}, {49, 625}, {128, 1125}, {98, 625}, {8, 51}, {64, 375}, {196, 625}, {16, 51}, {128, 375}, {249, 397}, {32, 51}, {185, 271} };
#elif (F_PLL==96000000)
  const tmclk clkArr[numfreqs] = {{8, 375}, {73, 2483}, {16, 375}, {147, 2500}, {32, 375}, {147, 1250}, {2, 17}, {16, 125}, {147, 625}, {4, 17}, {32, 125}, {151, 321}, {8, 17}, {64, 125} };
#elif (F_PLL==120000000)
  const tmclk clkArr[numfreqs] = {{32, 1875}, {89, 3784}, {64, 1875}, {147, 3125}, {128, 1875}, {205, 2179}, {8, 85}, {64, 625}, {89, 473}, {16, 85}, {128, 625}, {178, 473}, {32, 85}, {145, 354} };
#elif (F_PLL==144000000)
  const tmclk clkArr[numfreqs] = {{16, 1125}, {49, 2500}, {32, 1125}, {49, 1250}, {64, 1125}, {49, 625}, {4, 51}, {32, 375}, {98, 625}, {8, 51}, {64, 375}, {196, 625}, {16, 51}, {128, 375} };
#elif (F_PLL==168000000)
  const tmclk clkArr[numfreqs] = {{32, 2625}, {21, 1250}, {64, 2625}, {21, 625}, {128, 2625}, {42, 625}, {8, 119}, {64, 875}, {84, 625}, {16, 119}, {128, 875}, {168, 625}, {32, 119}, {189, 646} };	
#elif (F_PLL==180000000)
  const tmclk clkArr[numfreqs] = {{46, 4043}, {49, 3125}, {73, 3208}, {98, 3125}, {183, 4021}, {196, 3125}, {16, 255}, {128, 1875}, {107, 853}, {32, 255}, {219, 1604}, {214, 853}, {64, 255}, {219, 802} };
#elif (F_PLL==192000000)
  const tmclk clkArr[numfreqs] = {{4, 375}, {37, 2517}, {8, 375}, {73, 2483}, {16, 375}, {147, 2500}, {1, 17}, {8, 125}, {147, 1250}, {2, 17}, {16, 125}, {147, 625}, {4, 17}, {32, 125} };
#elif (F_PLL==216000000)
  const tmclk clkArr[numfreqs] = {{32, 3375}, {49, 3750}, {64, 3375}, {49, 1875}, {128, 3375}, {98, 1875}, {8, 153}, {64, 1125}, {196, 1875}, {16, 153}, {128, 1125}, {226, 1081}, {32, 153}, {147, 646} };
#elif (F_PLL==240000000)
  const tmclk clkArr[numfreqs] = {{16, 1875}, {29, 2466}, {32, 1875}, {89, 3784}, {64, 1875}, {147, 3125}, {4, 85}, {32, 625}, {205, 2179}, {8, 85}, {64, 625}, {89, 473}, {16, 85}, {128, 625} };
#elif (F_PLL==256000000)
  // TODO: fix these...
  const tmclk clkArr[numfreqs] = {{16, 1875}, {29, 2466}, {32, 1875}, {89, 3784}, {64, 1875}, {147, 3125}, {4, 85}, {32, 625}, {205, 2179}, {8, 85}, {64, 625}, {89, 473}, {16, 85}, {128, 625} };
#endif

  for (int f = 0; f < numfreqs; f++) {
    if ( freq == samplefreqs[f] ) {
      while (I2S0_MCR & I2S_MCR_DUF) ;
      I2S0_MDR = I2S_MDR_FRACT((clkArr[f].mult - 1)) | I2S_MDR_DIVIDE((clkArr[f].div - 1));
      return;
    }
  }
} #endif */

#elif defined(KINETISL)

void AudioOutputADAT::update(void)
{

	audio_block_t *block;
	block = receiveReadOnly(0); // input 0 = ch1 channel
	if (block) release(block);
	block = receiveReadOnly(1); // input 1 = ch2 channel
	if (block) release(block);
	block = receiveReadOnly(2); // input 2 = ch3 channel
	if (block) release(block);
	block = receiveReadOnly(3); // input 3 = ch4 channel
	if (block) release(block);
	block = receiveReadOnly(4); // input 4 = ch5 channel
	if (block) release(block);
	block = receiveReadOnly(5); // input 5 = ch6 channel
	if (block) release(block);
	block = receiveReadOnly(6); // input 6 = ch7 channel
	if (block) release(block);
	block = receiveReadOnly(7); // input 7 = ch8 channel
	if (block) release(block);
}

#endif

feel free to tell me if I am miles off the mark and waisting my time! -A
 
The bit of code I needed was actually in the orig output_adat.cpp..

I2S1_TCR4 = I2S_TCR4_FRSZ(7) should set I2S1_TCR4 to 8 words per frame. Sadly I still get just the noise on the first two channels. Almost as if the data isn't getting put out to the other 6.


Anyone have any ideas? -A
 
TAnyone have any ideas? -A
Have you added the needed cache-handling?
The contens of the cache need to written to RAM before DMA can use it.
You can see how it works i.e. in I2S Ouput. It's one call to a function.
 
Ta for the reply, I just had a look in i2s output as suggested and also output_spdif but I cant see the point where the cache-handling is happening. Would you mind showing me where this is happening and I will see if I have left it out of my copy paste special
 
Thanks Frank! I have added the line as suggested and I now get a texture/crackle less like noise and more like its trying to be a sound. Here is the code as it is as the moment:

Code:
/* ADAT for Teensy 3.X
 * Copyright (c) 2017, Ernstjan Freriks,
 * Thanks to Frank Bösing & KPC & Paul Stoffregen!
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice, development funding notice, and this permission
 * notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include <Arduino.h>
#include "output_adat.h"
#include "utility/imxrt_hw.h"


#if defined(KINETISK) || defined(__IMXRT1052__) || defined(__IMXRT1062__) //AAA

audio_block_t * AudioOutputADAT::block_ch1_1st = NULL;
audio_block_t * AudioOutputADAT::block_ch2_1st = NULL;
audio_block_t * AudioOutputADAT::block_ch3_1st = NULL;
audio_block_t * AudioOutputADAT::block_ch4_1st = NULL;
audio_block_t * AudioOutputADAT::block_ch5_1st = NULL;
audio_block_t * AudioOutputADAT::block_ch6_1st = NULL;
audio_block_t * AudioOutputADAT::block_ch7_1st = NULL;
audio_block_t * AudioOutputADAT::block_ch8_1st = NULL;

audio_block_t * AudioOutputADAT::block_ch1_2nd = NULL;
audio_block_t * AudioOutputADAT::block_ch2_2nd = NULL;
audio_block_t * AudioOutputADAT::block_ch3_2nd = NULL;
audio_block_t * AudioOutputADAT::block_ch4_2nd = NULL;
audio_block_t * AudioOutputADAT::block_ch5_2nd = NULL;
audio_block_t * AudioOutputADAT::block_ch6_2nd = NULL;
audio_block_t * AudioOutputADAT::block_ch7_2nd = NULL;
audio_block_t * AudioOutputADAT::block_ch8_2nd = NULL;

uint16_t  AudioOutputADAT::ch1_offset = 0;
uint16_t  AudioOutputADAT::ch2_offset = 0;
uint16_t  AudioOutputADAT::ch3_offset = 0;
uint16_t  AudioOutputADAT::ch4_offset = 0;
uint16_t  AudioOutputADAT::ch5_offset = 0;
uint16_t  AudioOutputADAT::ch6_offset = 0;
uint16_t  AudioOutputADAT::ch7_offset = 0;
uint16_t  AudioOutputADAT::ch8_offset = 0;

bool AudioOutputADAT::update_responsibility = false;
//uint32_t  AudioOutputADAT::vucp = VUCP_VALID;

DMAMEM static uint32_t ADAT_tx_buffer[AUDIO_BLOCK_SAMPLES * 8]; //4 KB, AUDIO_BLOCK_SAMPLES is usually 128
//DMAMEM __attribute__((aligned(32))) //AAA
DMAChannel AudioOutputADAT::dma(false);

static const uint32_t zerodata[AUDIO_BLOCK_SAMPLES/4] = {0};

// These are the lookup tables. There are four of them so that the remainder of the 32 bit result can easily be XORred with the next 8 bits.
static const uint32_t LookupTable_firstword[256]  = { 0x0, 0x1ffffff, 0x3ffffff, 0x2000000, 0x7ffffff, 0x6000000, 0x4000000, 0x5ffffff, 0xfffffff, 0xe000000, 0xc000000, 0xdffffff, 0x8000000, 0x9ffffff, 0xbffffff, 0xa000000, 0x1fffffff, 0x1e000000, 0x1c000000, 0x1dffffff, 0x18000000, 0x19ffffff, 0x1bffffff, 0x1a000000, 0x10000000, 0x11ffffff, 0x13ffffff, 0x12000000, 0x17ffffff, 0x16000000, 0x14000000, 0x15ffffff, 0x3fffffff, 0x3e000000, 0x3c000000, 0x3dffffff, 0x38000000, 0x39ffffff, 0x3bffffff, 0x3a000000, 0x30000000, 0x31ffffff, 0x33ffffff, 0x32000000, 0x37ffffff, 0x36000000, 0x34000000, 0x35ffffff, 0x20000000, 0x21ffffff, 0x23ffffff, 0x22000000, 0x27ffffff, 0x26000000, 0x24000000, 0x25ffffff, 0x2fffffff, 0x2e000000, 0x2c000000, 0x2dffffff, 0x28000000, 0x29ffffff, 0x2bffffff, 0x2a000000, 0x7fffffff, 0x7e000000, 0x7c000000, 0x7dffffff, 0x78000000, 0x79ffffff, 0x7bffffff, 0x7a000000, 0x70000000, 0x71ffffff, 0x73ffffff, 0x72000000, 0x77ffffff, 0x76000000, 0x74000000, 0x75ffffff, 0x60000000, 0x61ffffff, 0x63ffffff, 0x62000000, 0x67ffffff, 0x66000000, 0x64000000, 0x65ffffff, 0x6fffffff, 0x6e000000, 0x6c000000, 0x6dffffff, 0x68000000, 0x69ffffff, 0x6bffffff, 0x6a000000, 0x40000000, 0x41ffffff, 0x43ffffff, 0x42000000, 0x47ffffff, 0x46000000, 0x44000000, 0x45ffffff, 0x4fffffff, 0x4e000000, 0x4c000000, 0x4dffffff, 0x48000000, 0x49ffffff, 0x4bffffff, 0x4a000000, 0x5fffffff, 0x5e000000, 0x5c000000, 0x5dffffff, 0x58000000, 0x59ffffff, 0x5bffffff, 0x5a000000, 0x50000000, 0x51ffffff, 0x53ffffff, 0x52000000, 0x57ffffff, 0x56000000, 0x54000000, 0x55ffffff, 0xffffffff, 0xfe000000, 0xfc000000, 0xfdffffff, 0xf8000000, 0xf9ffffff, 0xfbffffff, 0xfa000000, 0xf0000000, 0xf1ffffff, 0xf3ffffff, 0xf2000000, 0xf7ffffff, 0xf6000000, 0xf4000000, 0xf5ffffff, 0xe0000000, 0xe1ffffff, 0xe3ffffff, 0xe2000000, 0xe7ffffff, 0xe6000000, 0xe4000000, 0xe5ffffff, 0xefffffff, 0xee000000, 0xec000000, 0xedffffff, 0xe8000000, 0xe9ffffff, 0xebffffff, 0xea000000, 0xc0000000, 0xc1ffffff, 0xc3ffffff, 0xc2000000, 0xc7ffffff, 0xc6000000, 0xc4000000, 0xc5ffffff, 0xcfffffff, 0xce000000, 0xcc000000, 0xcdffffff, 0xc8000000, 0xc9ffffff, 0xcbffffff, 0xca000000, 0xdfffffff, 0xde000000, 0xdc000000, 0xddffffff, 0xd8000000, 0xd9ffffff, 0xdbffffff, 0xda000000, 0xd0000000, 0xd1ffffff, 0xd3ffffff, 0xd2000000, 0xd7ffffff, 0xd6000000, 0xd4000000, 0xd5ffffff, 0x80000000, 0x81ffffff, 0x83ffffff, 0x82000000, 0x87ffffff, 0x86000000, 0x84000000, 0x85ffffff, 0x8fffffff, 0x8e000000, 0x8c000000, 0x8dffffff, 0x88000000, 0x89ffffff, 0x8bffffff, 0x8a000000, 0x9fffffff, 0x9e000000, 0x9c000000, 0x9dffffff, 0x98000000, 0x99ffffff, 0x9bffffff, 0x9a000000, 0x90000000, 0x91ffffff, 0x93ffffff, 0x92000000, 0x97ffffff, 0x96000000, 0x94000000, 0x95ffffff, 0xbfffffff, 0xbe000000, 0xbc000000, 0xbdffffff, 0xb8000000, 0xb9ffffff, 0xbbffffff, 0xba000000, 0xb0000000, 0xb1ffffff, 0xb3ffffff, 0xb2000000, 0xb7ffffff, 0xb6000000, 0xb4000000, 0xb5ffffff, 0xa0000000, 0xa1ffffff, 0xa3ffffff, 0xa2000000, 0xa7ffffff, 0xa6000000, 0xa4000000, 0xa5ffffff, 0xafffffff, 0xae000000, 0xac000000, 0xadffffff, 0xa8000000, 0xa9ffffff, 0xabffffff, 0xaa000000};
static const uint32_t LookupTable_secondword[256] = { 0x0, 0x1ffff, 0x3ffff, 0x20000, 0x7ffff, 0x60000, 0x40000, 0x5ffff, 0xfffff, 0xe0000, 0xc0000, 0xdffff, 0x80000, 0x9ffff, 0xbffff, 0xa0000, 0x1fffff, 0x1e0000, 0x1c0000, 0x1dffff, 0x180000, 0x19ffff, 0x1bffff, 0x1a0000, 0x100000, 0x11ffff, 0x13ffff, 0x120000, 0x17ffff, 0x160000, 0x140000, 0x15ffff, 0x3fffff, 0x3e0000, 0x3c0000, 0x3dffff, 0x380000, 0x39ffff, 0x3bffff, 0x3a0000, 0x300000, 0x31ffff, 0x33ffff, 0x320000, 0x37ffff, 0x360000, 0x340000, 0x35ffff, 0x200000, 0x21ffff, 0x23ffff, 0x220000, 0x27ffff, 0x260000, 0x240000, 0x25ffff, 0x2fffff, 0x2e0000, 0x2c0000, 0x2dffff, 0x280000, 0x29ffff, 0x2bffff, 0x2a0000, 0x7fffff, 0x7e0000, 0x7c0000, 0x7dffff, 0x780000, 0x79ffff, 0x7bffff, 0x7a0000, 0x700000, 0x71ffff, 0x73ffff, 0x720000, 0x77ffff, 0x760000, 0x740000, 0x75ffff, 0x600000, 0x61ffff, 0x63ffff, 0x620000, 0x67ffff, 0x660000, 0x640000, 0x65ffff, 0x6fffff, 0x6e0000, 0x6c0000, 0x6dffff, 0x680000, 0x69ffff, 0x6bffff, 0x6a0000, 0x400000, 0x41ffff, 0x43ffff, 0x420000, 0x47ffff, 0x460000, 0x440000, 0x45ffff, 0x4fffff, 0x4e0000, 0x4c0000, 0x4dffff, 0x480000, 0x49ffff, 0x4bffff, 0x4a0000, 0x5fffff, 0x5e0000, 0x5c0000, 0x5dffff, 0x580000, 0x59ffff, 0x5bffff, 0x5a0000, 0x500000, 0x51ffff, 0x53ffff, 0x520000, 0x57ffff, 0x560000, 0x540000, 0x55ffff, 0xffffff, 0xfe0000, 0xfc0000, 0xfdffff, 0xf80000, 0xf9ffff, 0xfbffff, 0xfa0000, 0xf00000, 0xf1ffff, 0xf3ffff, 0xf20000, 0xf7ffff, 0xf60000, 0xf40000, 0xf5ffff, 0xe00000, 0xe1ffff, 0xe3ffff, 0xe20000, 0xe7ffff, 0xe60000, 0xe40000, 0xe5ffff, 0xefffff, 0xee0000, 0xec0000, 0xedffff, 0xe80000, 0xe9ffff, 0xebffff, 0xea0000, 0xc00000, 0xc1ffff, 0xc3ffff, 0xc20000, 0xc7ffff, 0xc60000, 0xc40000, 0xc5ffff, 0xcfffff, 0xce0000, 0xcc0000, 0xcdffff, 0xc80000, 0xc9ffff, 0xcbffff, 0xca0000, 0xdfffff, 0xde0000, 0xdc0000, 0xddffff, 0xd80000, 0xd9ffff, 0xdbffff, 0xda0000, 0xd00000, 0xd1ffff, 0xd3ffff, 0xd20000, 0xd7ffff, 0xd60000, 0xd40000, 0xd5ffff, 0x800000, 0x81ffff, 0x83ffff, 0x820000, 0x87ffff, 0x860000, 0x840000, 0x85ffff, 0x8fffff, 0x8e0000, 0x8c0000, 0x8dffff, 0x880000, 0x89ffff, 0x8bffff, 0x8a0000, 0x9fffff, 0x9e0000, 0x9c0000, 0x9dffff, 0x980000, 0x99ffff, 0x9bffff, 0x9a0000, 0x900000, 0x91ffff, 0x93ffff, 0x920000, 0x97ffff, 0x960000, 0x940000, 0x95ffff, 0xbfffff, 0xbe0000, 0xbc0000, 0xbdffff, 0xb80000, 0xb9ffff, 0xbbffff, 0xba0000, 0xb00000, 0xb1ffff, 0xb3ffff, 0xb20000, 0xb7ffff, 0xb60000, 0xb40000, 0xb5ffff, 0xa00000, 0xa1ffff, 0xa3ffff, 0xa20000, 0xa7ffff, 0xa60000, 0xa40000, 0xa5ffff, 0xafffff, 0xae0000, 0xac0000, 0xadffff, 0xa80000, 0xa9ffff, 0xabffff, 0xaa0000};
static const uint32_t LookupTable_thirdword[256]  = { 0x0, 0x1ff, 0x3ff, 0x200, 0x7ff, 0x600, 0x400, 0x5ff, 0xfff, 0xe00, 0xc00, 0xdff, 0x800, 0x9ff, 0xbff, 0xa00, 0x1fff, 0x1e00, 0x1c00, 0x1dff, 0x1800, 0x19ff, 0x1bff, 0x1a00, 0x1000, 0x11ff, 0x13ff, 0x1200, 0x17ff, 0x1600, 0x1400, 0x15ff, 0x3fff, 0x3e00, 0x3c00, 0x3dff, 0x3800, 0x39ff, 0x3bff, 0x3a00, 0x3000, 0x31ff, 0x33ff, 0x3200, 0x37ff, 0x3600, 0x3400, 0x35ff, 0x2000, 0x21ff, 0x23ff, 0x2200, 0x27ff, 0x2600, 0x2400, 0x25ff, 0x2fff, 0x2e00, 0x2c00, 0x2dff, 0x2800, 0x29ff, 0x2bff, 0x2a00, 0x7fff, 0x7e00, 0x7c00, 0x7dff, 0x7800, 0x79ff, 0x7bff, 0x7a00, 0x7000, 0x71ff, 0x73ff, 0x7200, 0x77ff, 0x7600, 0x7400, 0x75ff, 0x6000, 0x61ff, 0x63ff, 0x6200, 0x67ff, 0x6600, 0x6400, 0x65ff, 0x6fff, 0x6e00, 0x6c00, 0x6dff, 0x6800, 0x69ff, 0x6bff, 0x6a00, 0x4000, 0x41ff, 0x43ff, 0x4200, 0x47ff, 0x4600, 0x4400, 0x45ff, 0x4fff, 0x4e00, 0x4c00, 0x4dff, 0x4800, 0x49ff, 0x4bff, 0x4a00, 0x5fff, 0x5e00, 0x5c00, 0x5dff, 0x5800, 0x59ff, 0x5bff, 0x5a00, 0x5000, 0x51ff, 0x53ff, 0x5200, 0x57ff, 0x5600, 0x5400, 0x55ff, 0xffff, 0xfe00, 0xfc00, 0xfdff, 0xf800, 0xf9ff, 0xfbff, 0xfa00, 0xf000, 0xf1ff, 0xf3ff, 0xf200, 0xf7ff, 0xf600, 0xf400, 0xf5ff, 0xe000, 0xe1ff, 0xe3ff, 0xe200, 0xe7ff, 0xe600, 0xe400, 0xe5ff, 0xefff, 0xee00, 0xec00, 0xedff, 0xe800, 0xe9ff, 0xebff, 0xea00, 0xc000, 0xc1ff, 0xc3ff, 0xc200, 0xc7ff, 0xc600, 0xc400, 0xc5ff, 0xcfff, 0xce00, 0xcc00, 0xcdff, 0xc800, 0xc9ff, 0xcbff, 0xca00, 0xdfff, 0xde00, 0xdc00, 0xddff, 0xd800, 0xd9ff, 0xdbff, 0xda00, 0xd000, 0xd1ff, 0xd3ff, 0xd200, 0xd7ff, 0xd600, 0xd400, 0xd5ff, 0x8000, 0x81ff, 0x83ff, 0x8200, 0x87ff, 0x8600, 0x8400, 0x85ff, 0x8fff, 0x8e00, 0x8c00, 0x8dff, 0x8800, 0x89ff, 0x8bff, 0x8a00, 0x9fff, 0x9e00, 0x9c00, 0x9dff, 0x9800, 0x99ff, 0x9bff, 0x9a00, 0x9000, 0x91ff, 0x93ff, 0x9200, 0x97ff, 0x9600, 0x9400, 0x95ff, 0xbfff, 0xbe00, 0xbc00, 0xbdff, 0xb800, 0xb9ff, 0xbbff, 0xba00, 0xb000, 0xb1ff, 0xb3ff, 0xb200, 0xb7ff, 0xb600, 0xb400, 0xb5ff, 0xa000, 0xa1ff, 0xa3ff, 0xa200, 0xa7ff, 0xa600, 0xa400, 0xa5ff, 0xafff, 0xae00, 0xac00, 0xadff, 0xa800, 0xa9ff, 0xabff, 0xaa00};
static const uint32_t LookupTable_fourthword[256] = { 0x0, 0x1, 0x3, 0x2, 0x7, 0x6, 0x4, 0x5, 0xf, 0xe, 0xc, 0xd, 0x8, 0x9, 0xb, 0xa, 0x1f, 0x1e, 0x1c, 0x1d, 0x18, 0x19, 0x1b, 0x1a, 0x10, 0x11, 0x13, 0x12, 0x17, 0x16, 0x14, 0x15, 0x3f, 0x3e, 0x3c, 0x3d, 0x38, 0x39, 0x3b, 0x3a, 0x30, 0x31, 0x33, 0x32, 0x37, 0x36, 0x34, 0x35, 0x20, 0x21, 0x23, 0x22, 0x27, 0x26, 0x24, 0x25, 0x2f, 0x2e, 0x2c, 0x2d, 0x28, 0x29, 0x2b, 0x2a, 0x7f, 0x7e, 0x7c, 0x7d, 0x78, 0x79, 0x7b, 0x7a, 0x70, 0x71, 0x73, 0x72, 0x77, 0x76, 0x74, 0x75, 0x60, 0x61, 0x63, 0x62, 0x67, 0x66, 0x64, 0x65, 0x6f, 0x6e, 0x6c, 0x6d, 0x68, 0x69, 0x6b, 0x6a, 0x40, 0x41, 0x43, 0x42, 0x47, 0x46, 0x44, 0x45, 0x4f, 0x4e, 0x4c, 0x4d, 0x48, 0x49, 0x4b, 0x4a, 0x5f, 0x5e, 0x5c, 0x5d, 0x58, 0x59, 0x5b, 0x5a, 0x50, 0x51, 0x53, 0x52, 0x57, 0x56, 0x54, 0x55, 0xff, 0xfe, 0xfc, 0xfd, 0xf8, 0xf9, 0xfb, 0xfa, 0xf0, 0xf1, 0xf3, 0xf2, 0xf7, 0xf6, 0xf4, 0xf5, 0xe0, 0xe1, 0xe3, 0xe2, 0xe7, 0xe6, 0xe4, 0xe5, 0xef, 0xee, 0xec, 0xed, 0xe8, 0xe9, 0xeb, 0xea, 0xc0, 0xc1, 0xc3, 0xc2, 0xc7, 0xc6, 0xc4, 0xc5, 0xcf, 0xce, 0xcc, 0xcd, 0xc8, 0xc9, 0xcb, 0xca, 0xdf, 0xde, 0xdc, 0xdd, 0xd8, 0xd9, 0xdb, 0xda, 0xd0, 0xd1, 0xd3, 0xd2, 0xd7, 0xd6, 0xd4, 0xd5, 0x80, 0x81, 0x83, 0x82, 0x87, 0x86, 0x84, 0x85, 0x8f, 0x8e, 0x8c, 0x8d, 0x88, 0x89, 0x8b, 0x8a, 0x9f, 0x9e, 0x9c, 0x9d, 0x98, 0x99, 0x9b, 0x9a, 0x90, 0x91, 0x93, 0x92, 0x97, 0x96, 0x94, 0x95, 0xbf, 0xbe, 0xbc, 0xbd, 0xb8, 0xb9, 0xbb, 0xba, 0xb0, 0xb1, 0xb3, 0xb2, 0xb7, 0xb6, 0xb4, 0xb5, 0xa0, 0xa1, 0xa3, 0xa2, 0xa7, 0xa6, 0xa4, 0xa5, 0xaf, 0xae, 0xac, 0xad, 0xa8, 0xa9, 0xab, 0xaa};

void AudioOutputADAT::begin(void)
{

	dma.begin(true); // Allocate the DMA channel first

	block_ch1_1st = NULL;
	block_ch2_1st = NULL;
	block_ch3_1st = NULL;
	block_ch4_1st = NULL;
	block_ch5_1st = NULL;
	block_ch6_1st = NULL;
	block_ch7_1st = NULL;
	block_ch8_1st = NULL;

	// TODO: should we set & clear the I2S_TCSR_SR bit here?
	config_ADAT();
#if defined(KINETISK)
	CORE_PIN22_CONFIG = PORT_PCR_MUX(6); // pin 22, PTC1, I2S0_TXD0

	const int nbytes_mlno = 2 * 8; // 16 Bytes per minor loop

	dma.TCD->SADDR = ADAT_tx_buffer;
	dma.TCD->SOFF = 4;
	dma.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); //transfersize 2 = 32 bit, 5 = 32 byte
	dma.TCD->NBYTES_MLNO = nbytes_mlno;
	dma.TCD->SLAST = -sizeof(ADAT_tx_buffer);
	dma.TCD->DADDR = &I2S0_TDR0;
	dma.TCD->DOFF = 0;
	dma.TCD->CITER_ELINKNO = sizeof(ADAT_tx_buffer) / nbytes_mlno;
	dma.TCD->DLASTSGA = 0;
	dma.TCD->BITER_ELINKNO = sizeof(ADAT_tx_buffer) / nbytes_mlno;
	dma.TCD->CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR;
	dma.triggerAtHardwareEvent(DMAMUX_SOURCE_I2S0_TX);
	update_responsibility = update_setup();
	dma.enable();

	I2S0_TCSR |= I2S_TCSR_TE | I2S_TCSR_BCE | I2S_TCSR_FRDE | I2S_TCSR_FR;
	dma.attachInterrupt(isr);
#elif defined(__IMXRT1052__) || defined(__IMXRT1062__)

#if defined(__IMXRT1052__)
	CORE_PIN6_CONFIG  = 3;  //1:TX_DATA0
#elif defined(__IMXRT1062__)
	CORE_PIN7_CONFIG  = 3;  //1:TX_DATA0	
#endif		
	
	const int nbytes_mlno = 2 * 8; // 16 Bytes per minor loop

	dma.TCD->SADDR = ADAT_tx_buffer;
	dma.TCD->SOFF = 4;
	dma.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2);
	dma.TCD->NBYTES_MLNO = nbytes_mlno;
	dma.TCD->SLAST = -sizeof(ADAT_tx_buffer);
	dma.TCD->DADDR = &I2S1_TDR0;
	dma.TCD->DOFF = 0;
	dma.TCD->CITER_ELINKNO = sizeof(ADAT_tx_buffer) / nbytes_mlno;
	dma.TCD->DLASTSGA = 0;
	dma.TCD->BITER_ELINKNO = sizeof(ADAT_tx_buffer) / nbytes_mlno;
	dma.TCD->CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR;
	dma.triggerAtHardwareEvent(DMAMUX_SOURCE_SAI1_TX);
	update_responsibility = update_setup();
	dma.enable();

	I2S1_RCSR |= I2S_RCSR_RE;
	I2S1_TCSR |= I2S_TCSR_TE | I2S_TCSR_BCE | I2S_TCSR_FRDE | I2S_TCSR_FR;
	dma.attachInterrupt(isr);
#endif
}


/*

	https://ackspace.nl/wiki/ADAT_project
	https://github.com/xcore/sc_adat/blob/master/module_adat_tx/src/adat_tx_port.xc

	for information about the clock:

	http://cache.freescale.com/files/32bit/doc/app_note/AN4800.pdf

	We need a bitrate twice as high as the SPDIF example.
	Because BITCLK can not be the same as MCLK, but only half of MCLK, we need a 2*MCLK (so for 44100 samplerate we need 88200 MCLK)
*/

void AudioOutputADAT::isr(void)
{
	const int16_t *src1, *src2, *src3, *src4,*src5, *src6, *src7, *src8;
	const int16_t *zeros = (const int16_t *)zerodata;

	uint32_t *end, *dest;
	uint32_t saddr;
	uint32_t sample1, sample2, sample3, sample4, sample5, sample6, sample7, sample8;

	static uint32_t previousnrzi_highlow = 0; //this is used for the NZRI encoding to remember the last state.
	// if the result of the lookup table LSB is other than this lastbit, the result of the lookup table must be inverted.

	//static bool previousframeinverted=false;

	saddr = (uint32_t)(dma.TCD->SADDR);
	dma.clearInterrupt();
	if (saddr < (uint32_t)ADAT_tx_buffer + sizeof(ADAT_tx_buffer) / 2) {
		// DMA is transmitting the first half of the buffer
		// so we must fill the second half
		dest = (uint32_t *)&ADAT_tx_buffer[AUDIO_BLOCK_SAMPLES * 8/2];
		end = (uint32_t *)&ADAT_tx_buffer[AUDIO_BLOCK_SAMPLES * 8];
		if (AudioOutputADAT::update_responsibility) AudioStream::update_all();
	} else {
		// DMA is transmitting the second half of the buffer
		// so we must fill the first half
		dest = (uint32_t *)ADAT_tx_buffer;
		end = (uint32_t *)&ADAT_tx_buffer[AUDIO_BLOCK_SAMPLES * 8/2];
	}

	src1 = (block_ch1_1st) ? block_ch1_1st->data + ch1_offset : zeros;
	src2 = (block_ch2_1st) ? block_ch2_1st->data + ch2_offset : zeros;
	src3 = (block_ch3_1st) ? block_ch3_1st->data + ch3_offset : zeros;
	src4 = (block_ch4_1st) ? block_ch4_1st->data + ch4_offset : zeros;
	src5 = (block_ch5_1st) ? block_ch5_1st->data + ch5_offset : zeros;
	src6 = (block_ch6_1st) ? block_ch6_1st->data + ch6_offset : zeros;
	src7 = (block_ch7_1st) ? block_ch7_1st->data + ch7_offset : zeros;
	src8 = (block_ch8_1st) ? block_ch8_1st->data + ch8_offset : zeros;


	//Non-NZRI encoded 'empty' ADAT Frame
	/*     
	*(dest+0) = 0b10000100001000010000100001000010; // bit 0-31
	*(dest+1) = 0b00010000100001000010000100001000; // bit 32-63
	*(dest+2) = 0b01000010000100001000010000100001; // bit 64-95
	*(dest+3) = 0b00001000010000100001000010000100; // bit 96-127

	*(dest+4) = 0b00100001000010000100001000010000; // bit 128-159
	*(dest+5) = 0b10000100001000010000100001000010; // bit 160-191
	*(dest+6) = 0b00010000100001000010000100001000; // bit 192-223
	*(dest+7) = 0b01000010000100001000000000010000; // bit 224-255

	dest+=8;

	*/

	/*
	//NZRI encoded 'empty' ADAT Frame

	*(dest+0) = 0b11111000001111100000111110000011; // bit 0-31
	*(dest+1) = 0b11100000111110000011111000001111; // bit 32-63
	*(dest+2) = 0b10000011111000001111100000111110; // bit 64-95
	*(dest+3) = 0b00001111100000111110000011111000; // bit 96-127

	*(dest+4) = 0b00111110000011111000001111100000; // bit 128-159
	*(dest+5) = 0b11111000001111100000111110000011; // bit 160-191
	*(dest+6) = 0b11100000111110000011111000001111; // bit 192-223
	*(dest+7) = 0b10000011111000001111111111100000; // bit 224-255

	dest+=8;

	*/

	do
	{
		sample1 = (*src1++);
		sample2 = (*src2++);
		sample3 = (*src3++);
		sample4 = (*src4++);
		sample5 = (*src5++);
		sample6 = (*src6++);
		sample7 = (*src7++);
		sample8 = (*src8++);

		uint32_t value;
		uint32_t nzrivalue;

		value=				 0b10000100001000010000100001000010 /* bit  0-31 */ 
//							  b00000000000000001000000000000000 // start of 16 bit sample
			| ((sample1<<15)&0b01111000000000000000000000000000) 
			| ((sample1<<14)&0b00000011110000000000000000000000) 
			| ((sample1<<13)&0b00000000000111100000000000000000)   
			| ((sample1<<12)&0b00000000000000001111000000000000) 
			| ((sample2>>15)&0b00000000000000000000000000000001)
			; 
		nzrivalue = previousnrzi_highlow ^ (LookupTable_firstword[(byte)(value >> 24)] ^ LookupTable_secondword[(byte)(value >> 16)] ^ LookupTable_thirdword[(byte)(value >> 8)] ^ LookupTable_fourthword[(byte)value]);
		*(dest+0) = nzrivalue;
        previousnrzi_highlow = ((nzrivalue & 0b1) == 0b1) ? ~0U : 0U;
		
		value =				 0b00010000100001000010000100001000 /* bit 32-63 */ 
//							  b00000000000000001000100010001000 // start of 16 bit sample
			| ((sample2<<17)&0b11100000000000000000000000000000) 
			| ((sample2<<16)&0b00001111000000000000000000000000) 
			| ((sample2<<15)&0b00000000011110000000000000000000)   
			| ((sample2<<14)&0b00000000000000111100000000000000) 
			| ((sample3>>13)&0b00000000000000000000000000000111)
			; 
		nzrivalue = previousnrzi_highlow ^ (LookupTable_firstword[(byte)(value >> 24)] ^ LookupTable_secondword[(byte)(value >> 16)] ^ LookupTable_thirdword[(byte)(value >> 8)] ^ LookupTable_fourthword[(byte)value]);
		*(dest+1) = nzrivalue;
        previousnrzi_highlow = ((nzrivalue & 0b1) == 0b1) ? ~0U : 0U;


		value =				 0b01000010000100001000010000100001 /* bit 64-95 */ 
//							  b00000000000000001000000000000000 // start of 16 bit sample
			| ((sample3<<19)&0b10000000000000000000000000000000) 
			| ((sample3<<18)&0b00111100000000000000000000000000)  
			| ((sample3<<17)&0b00000001111000000000000000000000)  
			| ((sample3<<16)&0b00000000000011110000000000000000) 
			| ((sample4>>11)&0b00000000000000000000000000011110)
			;
		nzrivalue = previousnrzi_highlow ^ (LookupTable_firstword[(byte)(value >> 24)] ^ LookupTable_secondword[(byte)(value >> 16)] ^ LookupTable_thirdword[(byte)(value >> 8)] ^ LookupTable_fourthword[(byte)value]);
		*(dest+2) = nzrivalue;
        previousnrzi_highlow = ((nzrivalue & 0b1) == 0b1) ? ~0U : 0U;

		value =				 0b00001000010000100001000010000100 /* bit 96-127 */ 
//							  b00000000000000001000100010001000 // start of 16 bit sample
			| ((sample4<<20)&0b11110000000000000000000000000000) 
			| ((sample4<<19)&0b00000111100000000000000000000000) 
			| ((sample4<<18)&0b00000000001111000000000000000000) 
			| ((sample5>>9 )&0b00000000000000000000000001111000) 
			| ((sample5>>10)&0b00000000000000000000000000000011) 
			;
		nzrivalue = previousnrzi_highlow ^ (LookupTable_firstword[(byte)(value >> 24)] ^ LookupTable_secondword[(byte)(value >> 16)] ^ LookupTable_thirdword[(byte)(value >> 8)] ^ LookupTable_fourthword[(byte)value]);
		*(dest+3) = nzrivalue;
        previousnrzi_highlow = ((nzrivalue & 0b1) == 0b1) ? ~0U : 0U;

		value =				 0b00100001000010000100001000010000 /* bit 128-159 */ 
//							  b00000000000000001000100010001000 // start of 16 bit sample
			| ((sample5<<22)&0b11000000000000000000000000000000) 
			| ((sample5<<21)&0b00011110000000000000000000000000) 
			| ((sample5<<20)&0b00000000111100000000000000000000) 
			| ((sample6>>7 )&0b00000000000000000000000111100000) 
			| ((sample6>>8 )&0b00000000000000000000000000001111) 
			;
		nzrivalue = previousnrzi_highlow ^ (LookupTable_firstword[(byte)(value >> 24)] ^ LookupTable_secondword[(byte)(value >> 16)] ^ LookupTable_thirdword[(byte)(value >> 8)] ^ LookupTable_fourthword[(byte)value]);
		*(dest+4) = nzrivalue;
        previousnrzi_highlow = ((nzrivalue & 0b1) == 0b1) ? ~0U : 0U;

		value =				 0b10000100001000010000100001000010 /* bit 160-191 */
//							  b00000000000000001000100010001000 // start of 16 bit sample
			| ((sample6<<23)&0b01111000000000000000000000000000) 
			| ((sample6<<22)&0b00000011110000000000000000000000) 
			| ((sample7>>5 )&0b00000000000000000000011110000000) 
			| ((sample7>>6 )&0b00000000000000000000000000111100) 
			| ((sample7>>7 )&0b00000000000000000000000000000001) 
			;

		nzrivalue = previousnrzi_highlow ^ (LookupTable_firstword[(byte)(value >> 24)] ^ LookupTable_secondword[(byte)(value >> 16)] ^ LookupTable_thirdword[(byte)(value >> 8)] ^ LookupTable_fourthword[(byte)value]);
		*(dest+5) = nzrivalue;
        previousnrzi_highlow = ((nzrivalue & 0b1) == 0b1) ? ~0U : 0U;

		value =				 0b00010000100001000010000100001000 /* bit 192-223 */
//							  b00000000000000001000100010001000 // start of 16 bit sample
			| ((sample7<<25)&0b11100000000000000000000000000000) 
			| ((sample7<<24)&0b00001111000000000000000000000000) 
			| ((sample8>>3 )&0b00000000000000000001111000000000) 
			| ((sample8>>4 )&0b00000000000000000000000011110000) 
			| ((sample8>>5 )&0b00000000000000000000000000000111)
			;

		nzrivalue = previousnrzi_highlow ^ (LookupTable_firstword[(byte)(value >> 24)] ^ LookupTable_secondword[(byte)(value >> 16)] ^ LookupTable_thirdword[(byte)(value >> 8)] ^ LookupTable_fourthword[(byte)value]);
		*(dest+6) = nzrivalue;
        previousnrzi_highlow = ((nzrivalue & 0b1) == 0b1) ? ~0U : 0U;

		value =				 0b01000010000100001000000000010000 /* bit 224-255 */
//							  b00000000000000001000100010001000 // start of 16 bit sample
			| ((sample8<<27)&0b10000000000000000000000000000000) 
			| ((sample8<<26)&0b00111100000000000000000000000000) 
			;

		nzrivalue = previousnrzi_highlow ^ (LookupTable_firstword[(byte)(value >> 24)] ^ LookupTable_secondword[(byte)(value >> 16)] ^ LookupTable_thirdword[(byte)(value >> 8)] ^ LookupTable_fourthword[(byte)value]);
		*(dest+7) = nzrivalue;
        previousnrzi_highlow = ((nzrivalue & 0b1) == 0b1) ? ~0U : 0U;

		dest+=8;
	} while (dest < end);
	/*
	block = AudioOutputADAT::block_ch1_1st;
	if (block) {
		offset = AudioOutputADAT::ch1_offset;
		src = &block->data[offset];
		do {

			sample = (uint32_t)*src++;

		} while (dest < end);
		offset += AUDIO_BLOCK_SAMPLES/2;
		if (offset < AUDIO_BLOCK_SAMPLES) {
			AudioOutputADAT::ch1_offset = offset;
		} else {
			AudioOutputADAT::ch1_offset = 0;
			AudioStream::release(block);
			AudioOutputADAT::block_ch1_1st = AudioOutputADAT::block_ch1_2nd;
			AudioOutputADAT::block_ch1_2nd = NULL;
		}
	} else {
		sample = 0;
	
		do {
			// *(dest+0) = 0b11111000001111100000111110000011; // bit 0-31
			// *(dest+1) = 0b11100000111110000011111000001111; // bit 32-63
			// *(dest+2) = 0b10000011111000001111100000111110; // bit 64-95
			// *(dest+3) = 0b00001111100000111110000011111000; // bit 96-127

			// *(dest+4) = 0b00111110000011111000001111100000; // bit 128-159
			// *(dest+5) = 0b11111000001111100000111110000011; // bit 160-191
			// *(dest+6) = 0b11100000111110000011111000001111; // bit 192-223
			// *(dest+7) = 0b10000011111000001111111111100000; // bit 224-255
			dest+=8;
		} while (dest < end);
	}

	
	dest -= AUDIO_BLOCK_SAMPLES * 8/2 - 8/2;
	block = AudioOutputADAT::block_ch2_1st;
	if (block) {
		offset = AudioOutputADAT::ch2_offset;
		src = &block->data[offset];

		do {
			sample = *src++;
			
			// *(dest+0) = 0b00111110000011111000001111100000; // bit 128-159
			// *(dest+1) = 0b11111000001111100000111110000011; // bit 160-191
			// *(dest+2) = 0b11100000111110000011111000001111; // bit 192-223
			// *(dest+3) = 0b10000011111000001111111111100000; // bit 224-255
			dest+=8;
		} while (dest < end);

		offset += AUDIO_BLOCK_SAMPLES/2;
		if (offset < AUDIO_BLOCK_SAMPLES) {
			AudioOutputADAT::ch2_offset = offset;
		} else {
			AudioOutputADAT::ch2_offset = 0;
			AudioStream::release(block);
			AudioOutputADAT::block_ch2_1st = AudioOutputADAT::block_ch2_2nd;
			AudioOutputADAT::block_ch2_2nd = NULL;
		}
	} else {
			// *(dest+0) = 0b00111110000011111000001111100000; // bit 128-159
			// *(dest+1) = 0b11111000001111100000111110000011; // bit 160-191
			// *(dest+2) = 0b11100000111110000011111000001111; // bit 192-223
			// *(dest+3) = 0b10000011111000001111111111100000; // bit 224-255
			dest+=8;
	}*/

	if (block_ch1_1st) {
		if (ch1_offset == 0) {
			ch1_offset = AUDIO_BLOCK_SAMPLES/2;
		} else {
			ch1_offset = 0;
			release(block_ch1_1st);
			block_ch1_1st = block_ch1_2nd;
			block_ch1_2nd = NULL;
		}
	}
	if (block_ch2_1st) {
		if (ch2_offset == 0) {
			ch2_offset = AUDIO_BLOCK_SAMPLES/2;
		} else {
			ch2_offset = 0;
			release(block_ch2_1st);
			block_ch2_1st = block_ch2_2nd;
			block_ch2_2nd = NULL;
		}
	}
	if (block_ch3_1st) {
		if (ch3_offset == 0) {
			ch3_offset = AUDIO_BLOCK_SAMPLES/2;
		} else {
			ch3_offset = 0;
			release(block_ch3_1st);
			block_ch3_1st = block_ch3_2nd;
			block_ch3_2nd = NULL;
		}
	}
	if (block_ch4_1st) {
		if (ch4_offset == 0) {
			ch4_offset = AUDIO_BLOCK_SAMPLES/2;
		} else {
			ch4_offset = 0;
			release(block_ch4_1st);
			block_ch4_1st = block_ch4_2nd;
			block_ch4_2nd = NULL;
		}
	}
	if (block_ch5_1st) {
		if (ch5_offset == 0) {
			ch5_offset = AUDIO_BLOCK_SAMPLES/2;
		} else {
			ch5_offset = 0;
			release(block_ch5_1st);
			block_ch5_1st = block_ch5_2nd;
			block_ch5_2nd = NULL;
		}
	}
	if (block_ch6_1st) {
		if (ch6_offset == 0) {
			ch6_offset = AUDIO_BLOCK_SAMPLES/2;
		} else {
			ch6_offset = 0;
			release(block_ch6_1st);
			block_ch6_1st = block_ch6_2nd;
			block_ch6_2nd = NULL;
		}
	}
	if (block_ch7_1st) {
		if (ch7_offset == 0) {
			ch7_offset = AUDIO_BLOCK_SAMPLES/2;
		} else {
			ch7_offset = 0;
			release(block_ch7_1st);
			block_ch7_1st = block_ch7_2nd;
			block_ch7_2nd = NULL;
		}
	}
	if (block_ch8_1st) {
		if (ch8_offset == 0) {
			ch8_offset = AUDIO_BLOCK_SAMPLES/2;
		} else {
			ch8_offset = 0;
			release(block_ch8_1st);
			block_ch8_1st = block_ch8_2nd;
			block_ch8_2nd = NULL;
		}
	}
    
    arm_dcache_flush_delete(dest, sizeof(ADAT_tx_buffer) / 2 );
    
}

void AudioOutputADAT::mute_PCM(const bool mute)
{
	//vucp = mute?VUCP_INVALID:VUCP_VALID;
	//#TODO
}

void AudioOutputADAT::update(void)
{

	audio_block_t *block, *tmp;

	block = receiveReadOnly(0); // input 0 = channel 1
	if (block) {
		__disable_irq();
		if (block_ch1_1st == NULL) {
			block_ch1_1st = block;
			ch1_offset = 0;
			__enable_irq();
		} else if (block_ch1_2nd == NULL) {
			block_ch1_2nd = block;
			__enable_irq();
		} else {
			tmp = block_ch1_1st;
			block_ch1_1st = block_ch1_2nd;
			block_ch1_2nd = block;
			ch1_offset = 0;
			__enable_irq();
			release(tmp);
		}
	}
	block = receiveReadOnly(1); // input 1 = channel 2
	if (block) {
		__disable_irq();
		if (block_ch2_1st == NULL) {
			block_ch2_1st = block;
			ch2_offset = 0;
			__enable_irq();
		} else if (block_ch2_2nd == NULL) {
			block_ch2_2nd = block;
			__enable_irq();
		} else {
			tmp = block_ch2_1st;
			block_ch2_1st = block_ch2_2nd;
			block_ch2_2nd = block;
			ch2_offset = 0;
			__enable_irq();
			release(tmp);
		}
	}
	block = receiveReadOnly(2); // channel 3
	if (block) {
		__disable_irq();
		if (block_ch3_1st == NULL) {
			block_ch3_1st = block;
			ch3_offset = 0;
			__enable_irq();
		} else if (block_ch3_2nd == NULL) {
			block_ch3_2nd = block;
			__enable_irq();
		} else {
			tmp = block_ch3_1st;
			block_ch3_1st = block_ch3_2nd;
			block_ch3_2nd = block;
			ch3_offset = 0;
			__enable_irq();
			release(tmp);
		}
	}
	block = receiveReadOnly(3); // channel 4
	if (block) {
		__disable_irq();
		if (block_ch4_1st == NULL) {
			block_ch4_1st = block;
			ch4_offset = 0;
			__enable_irq();
		} else if (block_ch4_2nd == NULL) {
			block_ch4_2nd = block;
			__enable_irq();
		} else {
			tmp = block_ch4_1st;
			block_ch4_1st = block_ch4_2nd;
			block_ch4_2nd = block;
			ch4_offset = 0;
			__enable_irq();
			release(tmp);
		}
	}
	block = receiveReadOnly(4); // channel 5
	if (block) {
		__disable_irq();
		if (block_ch5_1st == NULL) {
			block_ch5_1st = block;
			ch5_offset = 0;
			__enable_irq();
		} else if (block_ch5_2nd == NULL) {
			block_ch5_2nd = block;
			__enable_irq();
		} else {
			tmp = block_ch5_1st;
			block_ch5_1st = block_ch5_2nd;
			block_ch5_2nd = block;
			ch5_offset = 0;
			__enable_irq();
			release(tmp);
		}
	}
	block = receiveReadOnly(5); // channel 6
	if (block) {
		__disable_irq();
		if (block_ch6_1st == NULL) {
			block_ch6_1st = block;
			ch6_offset = 0;
			__enable_irq();
		} else if (block_ch6_2nd == NULL) {
			block_ch6_2nd = block;
			__enable_irq();
		} else {
			tmp = block_ch6_1st;
			block_ch6_1st = block_ch6_2nd;
			block_ch6_2nd = block;
			ch6_offset = 0;
			__enable_irq();
			release(tmp);
		}
	}
	block = receiveReadOnly(6); // channel 7
	if (block) {
		__disable_irq();
		if (block_ch7_1st == NULL) {
			block_ch7_1st = block;
			ch7_offset = 0;
			__enable_irq();
		} else if (block_ch7_2nd == NULL) {
			block_ch7_2nd = block;
			__enable_irq();
		} else {
			tmp = block_ch7_1st;
			block_ch7_1st = block_ch7_2nd;
			block_ch7_2nd = block;
			ch7_offset = 0;
			__enable_irq();
			release(tmp);
		}
	}
	block = receiveReadOnly(7); // channel 8
	if (block) {
		__disable_irq();
		if (block_ch8_1st == NULL) {
			block_ch8_1st = block;
			ch8_offset = 0;
			__enable_irq();
		} else if (block_ch8_2nd == NULL) {
			block_ch8_2nd = block;
			__enable_irq();
		} else {
			tmp = block_ch8_1st;
			block_ch8_1st = block_ch8_2nd;
			block_ch8_2nd = block;
			ch8_offset = 0;
			__enable_irq();
			release(tmp);
		}
	}
}


#if defined(KINETISK)
#if F_CPU == 96000000 || F_CPU == 48000000 || F_CPU == 24000000
  // PLL is at 96 MHz in these modes
  #define MCLK_MULT 2
  #define MCLK_DIV  17
#elif F_CPU == 72000000
  #define MCLK_MULT 8
  #define MCLK_DIV  51
#elif F_CPU == 120000000
  #define MCLK_MULT 8
  #define MCLK_DIV  85
#elif F_CPU == 144000000
  #define MCLK_MULT 4
  #define MCLK_DIV  51
#elif F_CPU == 168000000
  #define MCLK_MULT 8
  #define MCLK_DIV  119
#elif F_CPU == 180000000
  #define MCLK_MULT 16
  #define MCLK_DIV  255
  #define MCLK_SRC  0
#elif F_CPU == 192000000
  #define MCLK_MULT 1
  #define MCLK_DIV  17
#elif F_CPU == 216000000
  #define MCLK_MULT 12
  #define MCLK_DIV  17
  #define MCLK_SRC  1
#elif F_CPU == 240000000
  #define MCLK_MULT 2
  #define MCLK_DIV  85
  #define MCLK_SRC  0
#elif F_CPU == 256000000
  #define MCLK_MULT 12
  #define MCLK_DIV  17
  #define MCLK_SRC  1
#elif F_CPU == 16000000
  #define MCLK_MULT 12
  #define MCLK_DIV  17
#else
  #error "This CPU Clock Speed is not supported by the Audio library";
#endif

#ifndef MCLK_SRC
#if F_CPU >= 20000000
  #define MCLK_SRC  3  // the PLL
#else
  #define MCLK_SRC  0  // system clock
#endif
#endif
#endif

PROGMEM
void AudioOutputADAT::config_ADAT(void)
{
#if defined(KINETISK)
	SIM_SCGC6 |= SIM_SCGC6_I2S;
	SIM_SCGC7 |= SIM_SCGC7_DMA;
	SIM_SCGC6 |= SIM_SCGC6_DMAMUX;

	// enable MCLK output
	I2S0_MCR = I2S_MCR_MICS(MCLK_SRC) | I2S_MCR_MOE;
	//while (I2S0_MCR & I2S_MCR_DUF) ;
	//I2S0_MDR = I2S_MDR_FRACT((MCLK_MULT-1)) | I2S_MDR_DIVIDE((MCLK_DIV-1));

	AudioOutputADAT::setI2SFreq(88200);

	// configure transmitter
	I2S0_TMR = 0;
	I2S0_TCR1 = I2S_TCR1_TFW(1);  // watermark
	I2S0_TCR2 = I2S_TCR2_SYNC(0) | I2S_TCR2_MSEL(1) | I2S_TCR2_BCD | I2S_TCR2_DIV(0);
	I2S0_TCR3 = I2S_TCR3_TCE;

	//8 Words per Frame 32 Bit Word-Length -> 256 Bit Frame-Length, MSB First:
	I2S0_TCR4 = I2S_TCR4_FRSZ(7) | I2S_TCR4_SYWD(0) | I2S_TCR4_MF | I2S_TCR4_FSP | I2S_TCR4_FSD;
	I2S0_TCR5 = I2S_TCR5_WNW(31) | I2S_TCR5_W0W(31) | I2S_TCR5_FBT(31);

	I2S0_RCSR = 0;

#if 0
	// configure pin mux for 3 clock signals (debug only)
	CORE_PIN23_CONFIG = PORT_PCR_MUX(6); // pin 23, PTC2, I2S0_TX_FS (LRCLK)	44.1kHz
	CORE_PIN9_CONFIG  = PORT_PCR_MUX(6); // pin  9, PTC3, I2S0_TX_BCLK		5.6 MHz
	CORE_PIN11_CONFIG = PORT_PCR_MUX(6); // pin 11, PTC6, I2S0_MCLK			11.43MHz
#endif

#elif defined(__IMXRT1052__) || defined(__IMXRT1062__)
    
    

	CCM_CCGR5 |= CCM_CCGR5_SAI1(CCM_CCGR_ON);
    
    // if either transmitter or receiver is enabled, do nothing /AAA from output_i2s
	if (I2S1_TCSR & I2S_TCSR_TE) return;
	if (I2S1_RCSR & I2S_RCSR_RE) return;
    
//PLL:
	int fs = AUDIO_SAMPLE_RATE_EXACT;
	// PLL between 27*24 = 648MHz und 54*24=1296MHz
	int n1 = 4; //SAI prescaler 4 => (n1*n2) = multiple of 4
	int n2 = 1 + (24000000 * 27) / (fs * 256 * n1);

	double C = ((double)fs * 256 * n1 * n2) / 24000000;
	int c0 = C;
	int c2 = 10000;
	int c1 = C * c2 - (c0 * c2);
	set_audioClock(c0, c1, c2);

	CCM_CSCMR1 = (CCM_CSCMR1 & ~(CCM_CSCMR1_SAI1_CLK_SEL_MASK))
		   | CCM_CSCMR1_SAI1_CLK_SEL(2); // &0x03 // (0,1,2): PLL3PFD0, PLL5, PLL4
	CCM_CS1CDR = (CCM_CS1CDR & ~(CCM_CS1CDR_SAI1_CLK_PRED_MASK | CCM_CS1CDR_SAI1_CLK_PODF_MASK))
		   | CCM_CS1CDR_SAI1_CLK_PRED(n1-1) // &0x07
		   | CCM_CS1CDR_SAI1_CLK_PODF(n2-1); // &0x3f
    
    //Select MCLK
	IOMUXC_GPR_GPR1 = (IOMUXC_GPR_GPR1 & ~(IOMUXC_GPR_GPR1_SAI1_MCLK1_SEL_MASK))
			| (IOMUXC_GPR_GPR1_SAI1_MCLK_DIR | IOMUXC_GPR_GPR1_SAI1_MCLK1_SEL(0));	

	int rsync = 0;
	int tsync = 1;
    
	// configure transmitter
	I2S1_TMR = 0;
	I2S1_TCR1 = I2S_TCR1_RFW(0);  // watermark
	I2S1_TCR2 = I2S_TCR2_SYNC(tsync) | I2S_TCR2_MSEL(1) | I2S_TCR2_BCD | I2S_TCR2_DIV(0);
	I2S1_TCR3 = I2S_TCR3_TCE;

	// fix..4 Words per Frame 32 Bit Word-Length -> 128 Bit Frame-Length, MSB First:
    // i want.. 8 Words per Frame 32 Bit Word-Length -> 256 Bit Frame-Length, MSB First:
	I2S1_TCR4 = I2S_TCR4_FRSZ(7) | I2S_TCR4_SYWD(0) | I2S_TCR4_MF | I2S_TCR4_FSP | I2S_TCR4_FSD;
	I2S1_TCR5 = I2S_TCR5_WNW(31) | I2S_TCR5_W0W(31) | I2S_TCR5_FBT(31);
    
    //8 Words per Frame 32 Bit Word-Length -> 256 Bit Frame-Length, MSB First:
	//I2S0_TCR4 = I2S_TCR4_FRSZ(7) | I2S_TCR4_SYWD(0) | I2S_TCR4_MF | I2S_TCR4_FSP | //I2S_TCR4_FSD;
	//I2S0_TCR5 = I2S_TCR5_WNW(31) | I2S_TCR5_W0W(31) | I2S_TCR5_FBT(31);

	//I2S1_RCSR = 0;
	I2S1_RMR = 0;
	//I2S1_RCSR = (1<<25); //Reset
	I2S1_RCR1 = I2S_RCR1_RFW(0);
	I2S1_RCR2 = I2S_RCR2_SYNC(rsync) | I2S_TCR2_MSEL(1) | I2S_TCR2_BCD | I2S_TCR2_DIV(0);
	I2S1_RCR3 = I2S_RCR3_RCE;
	I2S1_RCR4 = I2S_TCR4_FRSZ(3) | I2S_TCR4_SYWD(0) | I2S_TCR4_MF | I2S_TCR4_FSP | I2S_TCR4_FSD;
	I2S1_RCR5 = I2S_TCR5_WNW(31) | I2S_TCR5_W0W(31) | I2S_TCR5_FBT(31);
    
    //AudioOutputADAT::setI2SFreq(88200);

#if 0
	//debug only:
	CORE_PIN23_CONFIG = 3;  //1:MCLK	11.43MHz
	CORE_PIN21_CONFIG = 3;  //1:RX_BCLK	5.6 MHz
	CORE_PIN20_CONFIG = 3;  //1:RX_SYNC	44.1 KHz
//	CORE_PIN6_CONFIG  = 3;  //1:TX_DATA0
//	CORE_PIN7_CONFIG  = 3;  //1:RX_DATA0
#endif

#endif
}

/*

https://forum.pjrc.com/threads/38753-Discussion-about-a-simple-way-to-change-the-sample-rate

*/



void AudioOutputADAT::setI2SFreq(int freq) {
     // PLL between 27*24 = 648MHz und 54*24=1296MHz
  int n1 = 4; //SAI prescaler 4 => (n1*n2) = multiple of 4
  int n2 = 1 + (24000000 * 27) / (freq * 256 * n1);
  double C = ((double)freq * 256 * n1 * n2) / 24000000;
  int c0 = C;
  int c2 = 10000;
  int c1 = C * c2 - (c0 * c2);
  set_audioClock(c0, c1, c2, true);
  CCM_CS1CDR = (CCM_CS1CDR & ~(CCM_CS1CDR_SAI1_CLK_PRED_MASK | CCM_CS1CDR_SAI1_CLK_PODF_MASK))
       | CCM_CS1CDR_SAI1_CLK_PRED(n1-1) // &0x07
       | CCM_CS1CDR_SAI1_CLK_PODF(n2-1); // &0x3f 
//Serial.printf("SetI2SFreq(%d)\n",freq);
} 

#elif defined(KINETISL)

void AudioOutputADAT::update(void)
{

	audio_block_t *block;
	block = receiveReadOnly(0); // input 0 = ch1 channel
	if (block) release(block);
	block = receiveReadOnly(1); // input 1 = ch2 channel
	if (block) release(block);
	block = receiveReadOnly(2); // input 2 = ch3 channel
	if (block) release(block);
	block = receiveReadOnly(3); // input 3 = ch4 channel
	if (block) release(block);
	block = receiveReadOnly(4); // input 4 = ch5 channel
	if (block) release(block);
	block = receiveReadOnly(5); // input 5 = ch6 channel
	if (block) release(block);
	block = receiveReadOnly(6); // input 6 = ch7 channel
	if (block) release(block);
	block = receiveReadOnly(7); // input 7 = ch8 channel
	if (block) release(block);
}

#endif

Can you suggest anything at this point? I am out of ideas.

edit: I also tried this code from output_spdif..

Code:
	#if IMXRT_CACHE_ENABLED >= 2
	dest -= AUDIO_BLOCK_SAMPLES * 4/2 + 4/2;
	arm_dcache_flush_delete(dest, sizeof(SPDIF_tx_buffer) / 2 );
	#endif
 
Suggestion: Take a break and try again tomorrow.. :)
I'm too tired to look over the long source (and I don't khow what exactly it does or should do .. )
Maybe tomorrow - it's late here.
 
A last hint for today:

in startup.c (in cores\tensy4\) you'll find these lines:
Code:
    SCB_MPU_RBAR = 0x20200000 | REGION(i++); // RAM (AXI bus)
    SCB_MPU_RASR = MEM_CACHE_WBWA | READWRITE | NOEXEC | SIZE_1M;
For a test - you can edit it the second line to
Code:
SCB_MPU_RASR = [COLOR=#ff0000]MEM_CACHE_WT[/COLOR] | READWRITE | NOEXEC | SIZE_1M;
This enables cache write-though
So.. you can check if your lines in the code re: cache-handling are correct.
If it sounds different now, your code is not correct.

It is important to get this right before looking for other problems.

Good night.
 
Thanks Frank! I have added the line as suggested and I now get a texture/crackle less like noise and more like its trying to be a sound. Here is the code as it is as the moment:

Code:
/* ADAT for Teensy 3.X
 * Copyright (c) 2017, Ernstjan Freriks,
 * Thanks to Frank Bösing & KPC & Paul Stoffregen!
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice, development funding notice, and this permission
 * notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include <Arduino.h>
#include "output_adat.h"
#include "utility/imxrt_hw.h"


#if defined(KINETISK) || defined(__IMXRT1052__) || defined(__IMXRT1062__) //AAA

audio_block_t * AudioOutputADAT::block_ch1_1st = NULL;
audio_block_t * AudioOutputADAT::block_ch2_1st = NULL;
audio_block_t * AudioOutputADAT::block_ch3_1st = NULL;
audio_block_t * AudioOutputADAT::block_ch4_1st = NULL;
audio_block_t * AudioOutputADAT::block_ch5_1st = NULL;
audio_block_t * AudioOutputADAT::block_ch6_1st = NULL;
audio_block_t * AudioOutputADAT::block_ch7_1st = NULL;
audio_block_t * AudioOutputADAT::block_ch8_1st = NULL;

audio_block_t * AudioOutputADAT::block_ch1_2nd = NULL;
audio_block_t * AudioOutputADAT::block_ch2_2nd = NULL;
audio_block_t * AudioOutputADAT::block_ch3_2nd = NULL;
audio_block_t * AudioOutputADAT::block_ch4_2nd = NULL;
audio_block_t * AudioOutputADAT::block_ch5_2nd = NULL;
audio_block_t * AudioOutputADAT::block_ch6_2nd = NULL;
audio_block_t * AudioOutputADAT::block_ch7_2nd = NULL;
audio_block_t * AudioOutputADAT::block_ch8_2nd = NULL;

uint16_t  AudioOutputADAT::ch1_offset = 0;
uint16_t  AudioOutputADAT::ch2_offset = 0;
uint16_t  AudioOutputADAT::ch3_offset = 0;
uint16_t  AudioOutputADAT::ch4_offset = 0;
uint16_t  AudioOutputADAT::ch5_offset = 0;
uint16_t  AudioOutputADAT::ch6_offset = 0;
uint16_t  AudioOutputADAT::ch7_offset = 0;
uint16_t  AudioOutputADAT::ch8_offset = 0;

bool AudioOutputADAT::update_responsibility = false;
//uint32_t  AudioOutputADAT::vucp = VUCP_VALID;

DMAMEM static uint32_t ADAT_tx_buffer[AUDIO_BLOCK_SAMPLES * 8]; //4 KB, AUDIO_BLOCK_SAMPLES is usually 128
//DMAMEM __attribute__((aligned(32))) //AAA
DMAChannel AudioOutputADAT::dma(false);

static const uint32_t zerodata[AUDIO_BLOCK_SAMPLES/4] = {0};

// These are the lookup tables. There are four of them so that the remainder of the 32 bit result can easily be XORred with the next 8 bits.
static const uint32_t LookupTable_firstword[256]  = { 0x0, 0x1ffffff, 0x3ffffff, 0x2000000, 0x7ffffff, 0x6000000, 0x4000000, 0x5ffffff, 0xfffffff, 0xe000000, 0xc000000, 0xdffffff, 0x8000000, 0x9ffffff, 0xbffffff, 0xa000000, 0x1fffffff, 0x1e000000, 0x1c000000, 0x1dffffff, 0x18000000, 0x19ffffff, 0x1bffffff, 0x1a000000, 0x10000000, 0x11ffffff, 0x13ffffff, 0x12000000, 0x17ffffff, 0x16000000, 0x14000000, 0x15ffffff, 0x3fffffff, 0x3e000000, 0x3c000000, 0x3dffffff, 0x38000000, 0x39ffffff, 0x3bffffff, 0x3a000000, 0x30000000, 0x31ffffff, 0x33ffffff, 0x32000000, 0x37ffffff, 0x36000000, 0x34000000, 0x35ffffff, 0x20000000, 0x21ffffff, 0x23ffffff, 0x22000000, 0x27ffffff, 0x26000000, 0x24000000, 0x25ffffff, 0x2fffffff, 0x2e000000, 0x2c000000, 0x2dffffff, 0x28000000, 0x29ffffff, 0x2bffffff, 0x2a000000, 0x7fffffff, 0x7e000000, 0x7c000000, 0x7dffffff, 0x78000000, 0x79ffffff, 0x7bffffff, 0x7a000000, 0x70000000, 0x71ffffff, 0x73ffffff, 0x72000000, 0x77ffffff, 0x76000000, 0x74000000, 0x75ffffff, 0x60000000, 0x61ffffff, 0x63ffffff, 0x62000000, 0x67ffffff, 0x66000000, 0x64000000, 0x65ffffff, 0x6fffffff, 0x6e000000, 0x6c000000, 0x6dffffff, 0x68000000, 0x69ffffff, 0x6bffffff, 0x6a000000, 0x40000000, 0x41ffffff, 0x43ffffff, 0x42000000, 0x47ffffff, 0x46000000, 0x44000000, 0x45ffffff, 0x4fffffff, 0x4e000000, 0x4c000000, 0x4dffffff, 0x48000000, 0x49ffffff, 0x4bffffff, 0x4a000000, 0x5fffffff, 0x5e000000, 0x5c000000, 0x5dffffff, 0x58000000, 0x59ffffff, 0x5bffffff, 0x5a000000, 0x50000000, 0x51ffffff, 0x53ffffff, 0x52000000, 0x57ffffff, 0x56000000, 0x54000000, 0x55ffffff, 0xffffffff, 0xfe000000, 0xfc000000, 0xfdffffff, 0xf8000000, 0xf9ffffff, 0xfbffffff, 0xfa000000, 0xf0000000, 0xf1ffffff, 0xf3ffffff, 0xf2000000, 0xf7ffffff, 0xf6000000, 0xf4000000, 0xf5ffffff, 0xe0000000, 0xe1ffffff, 0xe3ffffff, 0xe2000000, 0xe7ffffff, 0xe6000000, 0xe4000000, 0xe5ffffff, 0xefffffff, 0xee000000, 0xec000000, 0xedffffff, 0xe8000000, 0xe9ffffff, 0xebffffff, 0xea000000, 0xc0000000, 0xc1ffffff, 0xc3ffffff, 0xc2000000, 0xc7ffffff, 0xc6000000, 0xc4000000, 0xc5ffffff, 0xcfffffff, 0xce000000, 0xcc000000, 0xcdffffff, 0xc8000000, 0xc9ffffff, 0xcbffffff, 0xca000000, 0xdfffffff, 0xde000000, 0xdc000000, 0xddffffff, 0xd8000000, 0xd9ffffff, 0xdbffffff, 0xda000000, 0xd0000000, 0xd1ffffff, 0xd3ffffff, 0xd2000000, 0xd7ffffff, 0xd6000000, 0xd4000000, 0xd5ffffff, 0x80000000, 0x81ffffff, 0x83ffffff, 0x82000000, 0x87ffffff, 0x86000000, 0x84000000, 0x85ffffff, 0x8fffffff, 0x8e000000, 0x8c000000, 0x8dffffff, 0x88000000, 0x89ffffff, 0x8bffffff, 0x8a000000, 0x9fffffff, 0x9e000000, 0x9c000000, 0x9dffffff, 0x98000000, 0x99ffffff, 0x9bffffff, 0x9a000000, 0x90000000, 0x91ffffff, 0x93ffffff, 0x92000000, 0x97ffffff, 0x96000000, 0x94000000, 0x95ffffff, 0xbfffffff, 0xbe000000, 0xbc000000, 0xbdffffff, 0xb8000000, 0xb9ffffff, 0xbbffffff, 0xba000000, 0xb0000000, 0xb1ffffff, 0xb3ffffff, 0xb2000000, 0xb7ffffff, 0xb6000000, 0xb4000000, 0xb5ffffff, 0xa0000000, 0xa1ffffff, 0xa3ffffff, 0xa2000000, 0xa7ffffff, 0xa6000000, 0xa4000000, 0xa5ffffff, 0xafffffff, 0xae000000, 0xac000000, 0xadffffff, 0xa8000000, 0xa9ffffff, 0xabffffff, 0xaa000000};
static const uint32_t LookupTable_secondword[256] = { 0x0, 0x1ffff, 0x3ffff, 0x20000, 0x7ffff, 0x60000, 0x40000, 0x5ffff, 0xfffff, 0xe0000, 0xc0000, 0xdffff, 0x80000, 0x9ffff, 0xbffff, 0xa0000, 0x1fffff, 0x1e0000, 0x1c0000, 0x1dffff, 0x180000, 0x19ffff, 0x1bffff, 0x1a0000, 0x100000, 0x11ffff, 0x13ffff, 0x120000, 0x17ffff, 0x160000, 0x140000, 0x15ffff, 0x3fffff, 0x3e0000, 0x3c0000, 0x3dffff, 0x380000, 0x39ffff, 0x3bffff, 0x3a0000, 0x300000, 0x31ffff, 0x33ffff, 0x320000, 0x37ffff, 0x360000, 0x340000, 0x35ffff, 0x200000, 0x21ffff, 0x23ffff, 0x220000, 0x27ffff, 0x260000, 0x240000, 0x25ffff, 0x2fffff, 0x2e0000, 0x2c0000, 0x2dffff, 0x280000, 0x29ffff, 0x2bffff, 0x2a0000, 0x7fffff, 0x7e0000, 0x7c0000, 0x7dffff, 0x780000, 0x79ffff, 0x7bffff, 0x7a0000, 0x700000, 0x71ffff, 0x73ffff, 0x720000, 0x77ffff, 0x760000, 0x740000, 0x75ffff, 0x600000, 0x61ffff, 0x63ffff, 0x620000, 0x67ffff, 0x660000, 0x640000, 0x65ffff, 0x6fffff, 0x6e0000, 0x6c0000, 0x6dffff, 0x680000, 0x69ffff, 0x6bffff, 0x6a0000, 0x400000, 0x41ffff, 0x43ffff, 0x420000, 0x47ffff, 0x460000, 0x440000, 0x45ffff, 0x4fffff, 0x4e0000, 0x4c0000, 0x4dffff, 0x480000, 0x49ffff, 0x4bffff, 0x4a0000, 0x5fffff, 0x5e0000, 0x5c0000, 0x5dffff, 0x580000, 0x59ffff, 0x5bffff, 0x5a0000, 0x500000, 0x51ffff, 0x53ffff, 0x520000, 0x57ffff, 0x560000, 0x540000, 0x55ffff, 0xffffff, 0xfe0000, 0xfc0000, 0xfdffff, 0xf80000, 0xf9ffff, 0xfbffff, 0xfa0000, 0xf00000, 0xf1ffff, 0xf3ffff, 0xf20000, 0xf7ffff, 0xf60000, 0xf40000, 0xf5ffff, 0xe00000, 0xe1ffff, 0xe3ffff, 0xe20000, 0xe7ffff, 0xe60000, 0xe40000, 0xe5ffff, 0xefffff, 0xee0000, 0xec0000, 0xedffff, 0xe80000, 0xe9ffff, 0xebffff, 0xea0000, 0xc00000, 0xc1ffff, 0xc3ffff, 0xc20000, 0xc7ffff, 0xc60000, 0xc40000, 0xc5ffff, 0xcfffff, 0xce0000, 0xcc0000, 0xcdffff, 0xc80000, 0xc9ffff, 0xcbffff, 0xca0000, 0xdfffff, 0xde0000, 0xdc0000, 0xddffff, 0xd80000, 0xd9ffff, 0xdbffff, 0xda0000, 0xd00000, 0xd1ffff, 0xd3ffff, 0xd20000, 0xd7ffff, 0xd60000, 0xd40000, 0xd5ffff, 0x800000, 0x81ffff, 0x83ffff, 0x820000, 0x87ffff, 0x860000, 0x840000, 0x85ffff, 0x8fffff, 0x8e0000, 0x8c0000, 0x8dffff, 0x880000, 0x89ffff, 0x8bffff, 0x8a0000, 0x9fffff, 0x9e0000, 0x9c0000, 0x9dffff, 0x980000, 0x99ffff, 0x9bffff, 0x9a0000, 0x900000, 0x91ffff, 0x93ffff, 0x920000, 0x97ffff, 0x960000, 0x940000, 0x95ffff, 0xbfffff, 0xbe0000, 0xbc0000, 0xbdffff, 0xb80000, 0xb9ffff, 0xbbffff, 0xba0000, 0xb00000, 0xb1ffff, 0xb3ffff, 0xb20000, 0xb7ffff, 0xb60000, 0xb40000, 0xb5ffff, 0xa00000, 0xa1ffff, 0xa3ffff, 0xa20000, 0xa7ffff, 0xa60000, 0xa40000, 0xa5ffff, 0xafffff, 0xae0000, 0xac0000, 0xadffff, 0xa80000, 0xa9ffff, 0xabffff, 0xaa0000};
static const uint32_t LookupTable_thirdword[256]  = { 0x0, 0x1ff, 0x3ff, 0x200, 0x7ff, 0x600, 0x400, 0x5ff, 0xfff, 0xe00, 0xc00, 0xdff, 0x800, 0x9ff, 0xbff, 0xa00, 0x1fff, 0x1e00, 0x1c00, 0x1dff, 0x1800, 0x19ff, 0x1bff, 0x1a00, 0x1000, 0x11ff, 0x13ff, 0x1200, 0x17ff, 0x1600, 0x1400, 0x15ff, 0x3fff, 0x3e00, 0x3c00, 0x3dff, 0x3800, 0x39ff, 0x3bff, 0x3a00, 0x3000, 0x31ff, 0x33ff, 0x3200, 0x37ff, 0x3600, 0x3400, 0x35ff, 0x2000, 0x21ff, 0x23ff, 0x2200, 0x27ff, 0x2600, 0x2400, 0x25ff, 0x2fff, 0x2e00, 0x2c00, 0x2dff, 0x2800, 0x29ff, 0x2bff, 0x2a00, 0x7fff, 0x7e00, 0x7c00, 0x7dff, 0x7800, 0x79ff, 0x7bff, 0x7a00, 0x7000, 0x71ff, 0x73ff, 0x7200, 0x77ff, 0x7600, 0x7400, 0x75ff, 0x6000, 0x61ff, 0x63ff, 0x6200, 0x67ff, 0x6600, 0x6400, 0x65ff, 0x6fff, 0x6e00, 0x6c00, 0x6dff, 0x6800, 0x69ff, 0x6bff, 0x6a00, 0x4000, 0x41ff, 0x43ff, 0x4200, 0x47ff, 0x4600, 0x4400, 0x45ff, 0x4fff, 0x4e00, 0x4c00, 0x4dff, 0x4800, 0x49ff, 0x4bff, 0x4a00, 0x5fff, 0x5e00, 0x5c00, 0x5dff, 0x5800, 0x59ff, 0x5bff, 0x5a00, 0x5000, 0x51ff, 0x53ff, 0x5200, 0x57ff, 0x5600, 0x5400, 0x55ff, 0xffff, 0xfe00, 0xfc00, 0xfdff, 0xf800, 0xf9ff, 0xfbff, 0xfa00, 0xf000, 0xf1ff, 0xf3ff, 0xf200, 0xf7ff, 0xf600, 0xf400, 0xf5ff, 0xe000, 0xe1ff, 0xe3ff, 0xe200, 0xe7ff, 0xe600, 0xe400, 0xe5ff, 0xefff, 0xee00, 0xec00, 0xedff, 0xe800, 0xe9ff, 0xebff, 0xea00, 0xc000, 0xc1ff, 0xc3ff, 0xc200, 0xc7ff, 0xc600, 0xc400, 0xc5ff, 0xcfff, 0xce00, 0xcc00, 0xcdff, 0xc800, 0xc9ff, 0xcbff, 0xca00, 0xdfff, 0xde00, 0xdc00, 0xddff, 0xd800, 0xd9ff, 0xdbff, 0xda00, 0xd000, 0xd1ff, 0xd3ff, 0xd200, 0xd7ff, 0xd600, 0xd400, 0xd5ff, 0x8000, 0x81ff, 0x83ff, 0x8200, 0x87ff, 0x8600, 0x8400, 0x85ff, 0x8fff, 0x8e00, 0x8c00, 0x8dff, 0x8800, 0x89ff, 0x8bff, 0x8a00, 0x9fff, 0x9e00, 0x9c00, 0x9dff, 0x9800, 0x99ff, 0x9bff, 0x9a00, 0x9000, 0x91ff, 0x93ff, 0x9200, 0x97ff, 0x9600, 0x9400, 0x95ff, 0xbfff, 0xbe00, 0xbc00, 0xbdff, 0xb800, 0xb9ff, 0xbbff, 0xba00, 0xb000, 0xb1ff, 0xb3ff, 0xb200, 0xb7ff, 0xb600, 0xb400, 0xb5ff, 0xa000, 0xa1ff, 0xa3ff, 0xa200, 0xa7ff, 0xa600, 0xa400, 0xa5ff, 0xafff, 0xae00, 0xac00, 0xadff, 0xa800, 0xa9ff, 0xabff, 0xaa00};
static const uint32_t LookupTable_fourthword[256] = { 0x0, 0x1, 0x3, 0x2, 0x7, 0x6, 0x4, 0x5, 0xf, 0xe, 0xc, 0xd, 0x8, 0x9, 0xb, 0xa, 0x1f, 0x1e, 0x1c, 0x1d, 0x18, 0x19, 0x1b, 0x1a, 0x10, 0x11, 0x13, 0x12, 0x17, 0x16, 0x14, 0x15, 0x3f, 0x3e, 0x3c, 0x3d, 0x38, 0x39, 0x3b, 0x3a, 0x30, 0x31, 0x33, 0x32, 0x37, 0x36, 0x34, 0x35, 0x20, 0x21, 0x23, 0x22, 0x27, 0x26, 0x24, 0x25, 0x2f, 0x2e, 0x2c, 0x2d, 0x28, 0x29, 0x2b, 0x2a, 0x7f, 0x7e, 0x7c, 0x7d, 0x78, 0x79, 0x7b, 0x7a, 0x70, 0x71, 0x73, 0x72, 0x77, 0x76, 0x74, 0x75, 0x60, 0x61, 0x63, 0x62, 0x67, 0x66, 0x64, 0x65, 0x6f, 0x6e, 0x6c, 0x6d, 0x68, 0x69, 0x6b, 0x6a, 0x40, 0x41, 0x43, 0x42, 0x47, 0x46, 0x44, 0x45, 0x4f, 0x4e, 0x4c, 0x4d, 0x48, 0x49, 0x4b, 0x4a, 0x5f, 0x5e, 0x5c, 0x5d, 0x58, 0x59, 0x5b, 0x5a, 0x50, 0x51, 0x53, 0x52, 0x57, 0x56, 0x54, 0x55, 0xff, 0xfe, 0xfc, 0xfd, 0xf8, 0xf9, 0xfb, 0xfa, 0xf0, 0xf1, 0xf3, 0xf2, 0xf7, 0xf6, 0xf4, 0xf5, 0xe0, 0xe1, 0xe3, 0xe2, 0xe7, 0xe6, 0xe4, 0xe5, 0xef, 0xee, 0xec, 0xed, 0xe8, 0xe9, 0xeb, 0xea, 0xc0, 0xc1, 0xc3, 0xc2, 0xc7, 0xc6, 0xc4, 0xc5, 0xcf, 0xce, 0xcc, 0xcd, 0xc8, 0xc9, 0xcb, 0xca, 0xdf, 0xde, 0xdc, 0xdd, 0xd8, 0xd9, 0xdb, 0xda, 0xd0, 0xd1, 0xd3, 0xd2, 0xd7, 0xd6, 0xd4, 0xd5, 0x80, 0x81, 0x83, 0x82, 0x87, 0x86, 0x84, 0x85, 0x8f, 0x8e, 0x8c, 0x8d, 0x88, 0x89, 0x8b, 0x8a, 0x9f, 0x9e, 0x9c, 0x9d, 0x98, 0x99, 0x9b, 0x9a, 0x90, 0x91, 0x93, 0x92, 0x97, 0x96, 0x94, 0x95, 0xbf, 0xbe, 0xbc, 0xbd, 0xb8, 0xb9, 0xbb, 0xba, 0xb0, 0xb1, 0xb3, 0xb2, 0xb7, 0xb6, 0xb4, 0xb5, 0xa0, 0xa1, 0xa3, 0xa2, 0xa7, 0xa6, 0xa4, 0xa5, 0xaf, 0xae, 0xac, 0xad, 0xa8, 0xa9, 0xab, 0xaa};

void AudioOutputADAT::begin(void)
{

	dma.begin(true); // Allocate the DMA channel first

	block_ch1_1st = NULL;
	block_ch2_1st = NULL;
	block_ch3_1st = NULL;
	block_ch4_1st = NULL;
	block_ch5_1st = NULL;
	block_ch6_1st = NULL;
	block_ch7_1st = NULL;
	block_ch8_1st = NULL;

	// TODO: should we set & clear the I2S_TCSR_SR bit here?
	config_ADAT();
#if defined(KINETISK)
	CORE_PIN22_CONFIG = PORT_PCR_MUX(6); // pin 22, PTC1, I2S0_TXD0

	const int nbytes_mlno = 2 * 8; // 16 Bytes per minor loop

	dma.TCD->SADDR = ADAT_tx_buffer;
	dma.TCD->SOFF = 4;
	dma.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2); //transfersize 2 = 32 bit, 5 = 32 byte
	dma.TCD->NBYTES_MLNO = nbytes_mlno;
	dma.TCD->SLAST = -sizeof(ADAT_tx_buffer);
	dma.TCD->DADDR = &I2S0_TDR0;
	dma.TCD->DOFF = 0;
	dma.TCD->CITER_ELINKNO = sizeof(ADAT_tx_buffer) / nbytes_mlno;
	dma.TCD->DLASTSGA = 0;
	dma.TCD->BITER_ELINKNO = sizeof(ADAT_tx_buffer) / nbytes_mlno;
	dma.TCD->CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR;
	dma.triggerAtHardwareEvent(DMAMUX_SOURCE_I2S0_TX);
	update_responsibility = update_setup();
	dma.enable();

	I2S0_TCSR |= I2S_TCSR_TE | I2S_TCSR_BCE | I2S_TCSR_FRDE | I2S_TCSR_FR;
	dma.attachInterrupt(isr);
#elif defined(__IMXRT1052__) || defined(__IMXRT1062__)

#if defined(__IMXRT1052__)
	CORE_PIN6_CONFIG  = 3;  //1:TX_DATA0
#elif defined(__IMXRT1062__)
	CORE_PIN7_CONFIG  = 3;  //1:TX_DATA0	
#endif		
	
	const int nbytes_mlno = 2 * 8; // 16 Bytes per minor loop

	dma.TCD->SADDR = ADAT_tx_buffer;
	dma.TCD->SOFF = 4;
	dma.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2);
	dma.TCD->NBYTES_MLNO = nbytes_mlno;
	dma.TCD->SLAST = -sizeof(ADAT_tx_buffer);
	dma.TCD->DADDR = &I2S1_TDR0;
	dma.TCD->DOFF = 0;
	dma.TCD->CITER_ELINKNO = sizeof(ADAT_tx_buffer) / nbytes_mlno;
	dma.TCD->DLASTSGA = 0;
	dma.TCD->BITER_ELINKNO = sizeof(ADAT_tx_buffer) / nbytes_mlno;
	dma.TCD->CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR;
	dma.triggerAtHardwareEvent(DMAMUX_SOURCE_SAI1_TX);
	update_responsibility = update_setup();
	dma.enable();

	I2S1_RCSR |= I2S_RCSR_RE;
	I2S1_TCSR |= I2S_TCSR_TE | I2S_TCSR_BCE | I2S_TCSR_FRDE | I2S_TCSR_FR;
	dma.attachInterrupt(isr);
#endif
}


/*

	https://ackspace.nl/wiki/ADAT_project
	https://github.com/xcore/sc_adat/blob/master/module_adat_tx/src/adat_tx_port.xc

	for information about the clock:

	http://cache.freescale.com/files/32bit/doc/app_note/AN4800.pdf

	We need a bitrate twice as high as the SPDIF example.
	Because BITCLK can not be the same as MCLK, but only half of MCLK, we need a 2*MCLK (so for 44100 samplerate we need 88200 MCLK)
*/

void AudioOutputADAT::isr(void)
{
	const int16_t *src1, *src2, *src3, *src4,*src5, *src6, *src7, *src8;
	const int16_t *zeros = (const int16_t *)zerodata;

	uint32_t *end, *dest;
	uint32_t saddr;
	uint32_t sample1, sample2, sample3, sample4, sample5, sample6, sample7, sample8;

	static uint32_t previousnrzi_highlow = 0; //this is used for the NZRI encoding to remember the last state.
	// if the result of the lookup table LSB is other than this lastbit, the result of the lookup table must be inverted.

	//static bool previousframeinverted=false;

	saddr = (uint32_t)(dma.TCD->SADDR);
	dma.clearInterrupt();
	if (saddr < (uint32_t)ADAT_tx_buffer + sizeof(ADAT_tx_buffer) / 2) {
		// DMA is transmitting the first half of the buffer
		// so we must fill the second half
		dest = (uint32_t *)&ADAT_tx_buffer[AUDIO_BLOCK_SAMPLES * 8/2];
		end = (uint32_t *)&ADAT_tx_buffer[AUDIO_BLOCK_SAMPLES * 8];
		if (AudioOutputADAT::update_responsibility) AudioStream::update_all();
	} else {
		// DMA is transmitting the second half of the buffer
		// so we must fill the first half
		dest = (uint32_t *)ADAT_tx_buffer;
		end = (uint32_t *)&ADAT_tx_buffer[AUDIO_BLOCK_SAMPLES * 8/2];
	}

	src1 = (block_ch1_1st) ? block_ch1_1st->data + ch1_offset : zeros;
	src2 = (block_ch2_1st) ? block_ch2_1st->data + ch2_offset : zeros;
	src3 = (block_ch3_1st) ? block_ch3_1st->data + ch3_offset : zeros;
	src4 = (block_ch4_1st) ? block_ch4_1st->data + ch4_offset : zeros;
	src5 = (block_ch5_1st) ? block_ch5_1st->data + ch5_offset : zeros;
	src6 = (block_ch6_1st) ? block_ch6_1st->data + ch6_offset : zeros;
	src7 = (block_ch7_1st) ? block_ch7_1st->data + ch7_offset : zeros;
	src8 = (block_ch8_1st) ? block_ch8_1st->data + ch8_offset : zeros;


	//Non-NZRI encoded 'empty' ADAT Frame
	/*     
	*(dest+0) = 0b10000100001000010000100001000010; // bit 0-31
	*(dest+1) = 0b00010000100001000010000100001000; // bit 32-63
	*(dest+2) = 0b01000010000100001000010000100001; // bit 64-95
	*(dest+3) = 0b00001000010000100001000010000100; // bit 96-127

	*(dest+4) = 0b00100001000010000100001000010000; // bit 128-159
	*(dest+5) = 0b10000100001000010000100001000010; // bit 160-191
	*(dest+6) = 0b00010000100001000010000100001000; // bit 192-223
	*(dest+7) = 0b01000010000100001000000000010000; // bit 224-255

	dest+=8;

	*/

	/*
	//NZRI encoded 'empty' ADAT Frame

	*(dest+0) = 0b11111000001111100000111110000011; // bit 0-31
	*(dest+1) = 0b11100000111110000011111000001111; // bit 32-63
	*(dest+2) = 0b10000011111000001111100000111110; // bit 64-95
	*(dest+3) = 0b00001111100000111110000011111000; // bit 96-127

	*(dest+4) = 0b00111110000011111000001111100000; // bit 128-159
	*(dest+5) = 0b11111000001111100000111110000011; // bit 160-191
	*(dest+6) = 0b11100000111110000011111000001111; // bit 192-223
	*(dest+7) = 0b10000011111000001111111111100000; // bit 224-255

	dest+=8;

	*/

	do
	{
		sample1 = (*src1++);
		sample2 = (*src2++);
		sample3 = (*src3++);
		sample4 = (*src4++);
		sample5 = (*src5++);
		sample6 = (*src6++);
		sample7 = (*src7++);
		sample8 = (*src8++);

		uint32_t value;
		uint32_t nzrivalue;

		value=				 0b10000100001000010000100001000010 /* bit  0-31 */ 
//							  b00000000000000001000000000000000 // start of 16 bit sample
			| ((sample1<<15)&0b01111000000000000000000000000000) 
			| ((sample1<<14)&0b00000011110000000000000000000000) 
			| ((sample1<<13)&0b00000000000111100000000000000000)   
			| ((sample1<<12)&0b00000000000000001111000000000000) 
			| ((sample2>>15)&0b00000000000000000000000000000001)
			; 
		nzrivalue = previousnrzi_highlow ^ (LookupTable_firstword[(byte)(value >> 24)] ^ LookupTable_secondword[(byte)(value >> 16)] ^ LookupTable_thirdword[(byte)(value >> 8)] ^ LookupTable_fourthword[(byte)value]);
		*(dest+0) = nzrivalue;
        previousnrzi_highlow = ((nzrivalue & 0b1) == 0b1) ? ~0U : 0U;
		
		value =				 0b00010000100001000010000100001000 /* bit 32-63 */ 
//							  b00000000000000001000100010001000 // start of 16 bit sample
			| ((sample2<<17)&0b11100000000000000000000000000000) 
			| ((sample2<<16)&0b00001111000000000000000000000000) 
			| ((sample2<<15)&0b00000000011110000000000000000000)   
			| ((sample2<<14)&0b00000000000000111100000000000000) 
			| ((sample3>>13)&0b00000000000000000000000000000111)
			; 
		nzrivalue = previousnrzi_highlow ^ (LookupTable_firstword[(byte)(value >> 24)] ^ LookupTable_secondword[(byte)(value >> 16)] ^ LookupTable_thirdword[(byte)(value >> 8)] ^ LookupTable_fourthword[(byte)value]);
		*(dest+1) = nzrivalue;
        previousnrzi_highlow = ((nzrivalue & 0b1) == 0b1) ? ~0U : 0U;


		value =				 0b01000010000100001000010000100001 /* bit 64-95 */ 
//							  b00000000000000001000000000000000 // start of 16 bit sample
			| ((sample3<<19)&0b10000000000000000000000000000000) 
			| ((sample3<<18)&0b00111100000000000000000000000000)  
			| ((sample3<<17)&0b00000001111000000000000000000000)  
			| ((sample3<<16)&0b00000000000011110000000000000000) 
			| ((sample4>>11)&0b00000000000000000000000000011110)
			;
		nzrivalue = previousnrzi_highlow ^ (LookupTable_firstword[(byte)(value >> 24)] ^ LookupTable_secondword[(byte)(value >> 16)] ^ LookupTable_thirdword[(byte)(value >> 8)] ^ LookupTable_fourthword[(byte)value]);
		*(dest+2) = nzrivalue;
        previousnrzi_highlow = ((nzrivalue & 0b1) == 0b1) ? ~0U : 0U;

		value =				 0b00001000010000100001000010000100 /* bit 96-127 */ 
//							  b00000000000000001000100010001000 // start of 16 bit sample
			| ((sample4<<20)&0b11110000000000000000000000000000) 
			| ((sample4<<19)&0b00000111100000000000000000000000) 
			| ((sample4<<18)&0b00000000001111000000000000000000) 
			| ((sample5>>9 )&0b00000000000000000000000001111000) 
			| ((sample5>>10)&0b00000000000000000000000000000011) 
			;
		nzrivalue = previousnrzi_highlow ^ (LookupTable_firstword[(byte)(value >> 24)] ^ LookupTable_secondword[(byte)(value >> 16)] ^ LookupTable_thirdword[(byte)(value >> 8)] ^ LookupTable_fourthword[(byte)value]);
		*(dest+3) = nzrivalue;
        previousnrzi_highlow = ((nzrivalue & 0b1) == 0b1) ? ~0U : 0U;

		value =				 0b00100001000010000100001000010000 /* bit 128-159 */ 
//							  b00000000000000001000100010001000 // start of 16 bit sample
			| ((sample5<<22)&0b11000000000000000000000000000000) 
			| ((sample5<<21)&0b00011110000000000000000000000000) 
			| ((sample5<<20)&0b00000000111100000000000000000000) 
			| ((sample6>>7 )&0b00000000000000000000000111100000) 
			| ((sample6>>8 )&0b00000000000000000000000000001111) 
			;
		nzrivalue = previousnrzi_highlow ^ (LookupTable_firstword[(byte)(value >> 24)] ^ LookupTable_secondword[(byte)(value >> 16)] ^ LookupTable_thirdword[(byte)(value >> 8)] ^ LookupTable_fourthword[(byte)value]);
		*(dest+4) = nzrivalue;
        previousnrzi_highlow = ((nzrivalue & 0b1) == 0b1) ? ~0U : 0U;

		value =				 0b10000100001000010000100001000010 /* bit 160-191 */
//							  b00000000000000001000100010001000 // start of 16 bit sample
			| ((sample6<<23)&0b01111000000000000000000000000000) 
			| ((sample6<<22)&0b00000011110000000000000000000000) 
			| ((sample7>>5 )&0b00000000000000000000011110000000) 
			| ((sample7>>6 )&0b00000000000000000000000000111100) 
			| ((sample7>>7 )&0b00000000000000000000000000000001) 
			;

		nzrivalue = previousnrzi_highlow ^ (LookupTable_firstword[(byte)(value >> 24)] ^ LookupTable_secondword[(byte)(value >> 16)] ^ LookupTable_thirdword[(byte)(value >> 8)] ^ LookupTable_fourthword[(byte)value]);
		*(dest+5) = nzrivalue;
        previousnrzi_highlow = ((nzrivalue & 0b1) == 0b1) ? ~0U : 0U;

		value =				 0b00010000100001000010000100001000 /* bit 192-223 */
//							  b00000000000000001000100010001000 // start of 16 bit sample
			| ((sample7<<25)&0b11100000000000000000000000000000) 
			| ((sample7<<24)&0b00001111000000000000000000000000) 
			| ((sample8>>3 )&0b00000000000000000001111000000000) 
			| ((sample8>>4 )&0b00000000000000000000000011110000) 
			| ((sample8>>5 )&0b00000000000000000000000000000111)
			;

		nzrivalue = previousnrzi_highlow ^ (LookupTable_firstword[(byte)(value >> 24)] ^ LookupTable_secondword[(byte)(value >> 16)] ^ LookupTable_thirdword[(byte)(value >> 8)] ^ LookupTable_fourthword[(byte)value]);
		*(dest+6) = nzrivalue;
        previousnrzi_highlow = ((nzrivalue & 0b1) == 0b1) ? ~0U : 0U;

		value =				 0b01000010000100001000000000010000 /* bit 224-255 */
//							  b00000000000000001000100010001000 // start of 16 bit sample
			| ((sample8<<27)&0b10000000000000000000000000000000) 
			| ((sample8<<26)&0b00111100000000000000000000000000) 
			;

		nzrivalue = previousnrzi_highlow ^ (LookupTable_firstword[(byte)(value >> 24)] ^ LookupTable_secondword[(byte)(value >> 16)] ^ LookupTable_thirdword[(byte)(value >> 8)] ^ LookupTable_fourthword[(byte)value]);
		*(dest+7) = nzrivalue;
        previousnrzi_highlow = ((nzrivalue & 0b1) == 0b1) ? ~0U : 0U;

		dest+=8;
	} while (dest < end);
	/*
	block = AudioOutputADAT::block_ch1_1st;
	if (block) {
		offset = AudioOutputADAT::ch1_offset;
		src = &block->data[offset];
		do {

			sample = (uint32_t)*src++;

		} while (dest < end);
		offset += AUDIO_BLOCK_SAMPLES/2;
		if (offset < AUDIO_BLOCK_SAMPLES) {
			AudioOutputADAT::ch1_offset = offset;
		} else {
			AudioOutputADAT::ch1_offset = 0;
			AudioStream::release(block);
			AudioOutputADAT::block_ch1_1st = AudioOutputADAT::block_ch1_2nd;
			AudioOutputADAT::block_ch1_2nd = NULL;
		}
	} else {
		sample = 0;
	
		do {
			// *(dest+0) = 0b11111000001111100000111110000011; // bit 0-31
			// *(dest+1) = 0b11100000111110000011111000001111; // bit 32-63
			// *(dest+2) = 0b10000011111000001111100000111110; // bit 64-95
			// *(dest+3) = 0b00001111100000111110000011111000; // bit 96-127

			// *(dest+4) = 0b00111110000011111000001111100000; // bit 128-159
			// *(dest+5) = 0b11111000001111100000111110000011; // bit 160-191
			// *(dest+6) = 0b11100000111110000011111000001111; // bit 192-223
			// *(dest+7) = 0b10000011111000001111111111100000; // bit 224-255
			dest+=8;
		} while (dest < end);
	}

	
	dest -= AUDIO_BLOCK_SAMPLES * 8/2 - 8/2;
	block = AudioOutputADAT::block_ch2_1st;
	if (block) {
		offset = AudioOutputADAT::ch2_offset;
		src = &block->data[offset];

		do {
			sample = *src++;
			
			// *(dest+0) = 0b00111110000011111000001111100000; // bit 128-159
			// *(dest+1) = 0b11111000001111100000111110000011; // bit 160-191
			// *(dest+2) = 0b11100000111110000011111000001111; // bit 192-223
			// *(dest+3) = 0b10000011111000001111111111100000; // bit 224-255
			dest+=8;
		} while (dest < end);

		offset += AUDIO_BLOCK_SAMPLES/2;
		if (offset < AUDIO_BLOCK_SAMPLES) {
			AudioOutputADAT::ch2_offset = offset;
		} else {
			AudioOutputADAT::ch2_offset = 0;
			AudioStream::release(block);
			AudioOutputADAT::block_ch2_1st = AudioOutputADAT::block_ch2_2nd;
			AudioOutputADAT::block_ch2_2nd = NULL;
		}
	} else {
			// *(dest+0) = 0b00111110000011111000001111100000; // bit 128-159
			// *(dest+1) = 0b11111000001111100000111110000011; // bit 160-191
			// *(dest+2) = 0b11100000111110000011111000001111; // bit 192-223
			// *(dest+3) = 0b10000011111000001111111111100000; // bit 224-255
			dest+=8;
	}*/

	if (block_ch1_1st) {
		if (ch1_offset == 0) {
			ch1_offset = AUDIO_BLOCK_SAMPLES/2;
		} else {
			ch1_offset = 0;
			release(block_ch1_1st);
			block_ch1_1st = block_ch1_2nd;
			block_ch1_2nd = NULL;
		}
	}
	if (block_ch2_1st) {
		if (ch2_offset == 0) {
			ch2_offset = AUDIO_BLOCK_SAMPLES/2;
		} else {
			ch2_offset = 0;
			release(block_ch2_1st);
			block_ch2_1st = block_ch2_2nd;
			block_ch2_2nd = NULL;
		}
	}
	if (block_ch3_1st) {
		if (ch3_offset == 0) {
			ch3_offset = AUDIO_BLOCK_SAMPLES/2;
		} else {
			ch3_offset = 0;
			release(block_ch3_1st);
			block_ch3_1st = block_ch3_2nd;
			block_ch3_2nd = NULL;
		}
	}
	if (block_ch4_1st) {
		if (ch4_offset == 0) {
			ch4_offset = AUDIO_BLOCK_SAMPLES/2;
		} else {
			ch4_offset = 0;
			release(block_ch4_1st);
			block_ch4_1st = block_ch4_2nd;
			block_ch4_2nd = NULL;
		}
	}
	if (block_ch5_1st) {
		if (ch5_offset == 0) {
			ch5_offset = AUDIO_BLOCK_SAMPLES/2;
		} else {
			ch5_offset = 0;
			release(block_ch5_1st);
			block_ch5_1st = block_ch5_2nd;
			block_ch5_2nd = NULL;
		}
	}
	if (block_ch6_1st) {
		if (ch6_offset == 0) {
			ch6_offset = AUDIO_BLOCK_SAMPLES/2;
		} else {
			ch6_offset = 0;
			release(block_ch6_1st);
			block_ch6_1st = block_ch6_2nd;
			block_ch6_2nd = NULL;
		}
	}
	if (block_ch7_1st) {
		if (ch7_offset == 0) {
			ch7_offset = AUDIO_BLOCK_SAMPLES/2;
		} else {
			ch7_offset = 0;
			release(block_ch7_1st);
			block_ch7_1st = block_ch7_2nd;
			block_ch7_2nd = NULL;
		}
	}
	if (block_ch8_1st) {
		if (ch8_offset == 0) {
			ch8_offset = AUDIO_BLOCK_SAMPLES/2;
		} else {
			ch8_offset = 0;
			release(block_ch8_1st);
			block_ch8_1st = block_ch8_2nd;
			block_ch8_2nd = NULL;
		}
	}
    
    arm_dcache_flush_delete(dest, sizeof(ADAT_tx_buffer) / 2 );
    
}

void AudioOutputADAT::mute_PCM(const bool mute)
{
	//vucp = mute?VUCP_INVALID:VUCP_VALID;
	//#TODO
}

void AudioOutputADAT::update(void)
{

	audio_block_t *block, *tmp;

	block = receiveReadOnly(0); // input 0 = channel 1
	if (block) {
		__disable_irq();
		if (block_ch1_1st == NULL) {
			block_ch1_1st = block;
			ch1_offset = 0;
			__enable_irq();
		} else if (block_ch1_2nd == NULL) {
			block_ch1_2nd = block;
			__enable_irq();
		} else {
			tmp = block_ch1_1st;
			block_ch1_1st = block_ch1_2nd;
			block_ch1_2nd = block;
			ch1_offset = 0;
			__enable_irq();
			release(tmp);
		}
	}
	block = receiveReadOnly(1); // input 1 = channel 2
	if (block) {
		__disable_irq();
		if (block_ch2_1st == NULL) {
			block_ch2_1st = block;
			ch2_offset = 0;
			__enable_irq();
		} else if (block_ch2_2nd == NULL) {
			block_ch2_2nd = block;
			__enable_irq();
		} else {
			tmp = block_ch2_1st;
			block_ch2_1st = block_ch2_2nd;
			block_ch2_2nd = block;
			ch2_offset = 0;
			__enable_irq();
			release(tmp);
		}
	}
	block = receiveReadOnly(2); // channel 3
	if (block) {
		__disable_irq();
		if (block_ch3_1st == NULL) {
			block_ch3_1st = block;
			ch3_offset = 0;
			__enable_irq();
		} else if (block_ch3_2nd == NULL) {
			block_ch3_2nd = block;
			__enable_irq();
		} else {
			tmp = block_ch3_1st;
			block_ch3_1st = block_ch3_2nd;
			block_ch3_2nd = block;
			ch3_offset = 0;
			__enable_irq();
			release(tmp);
		}
	}
	block = receiveReadOnly(3); // channel 4
	if (block) {
		__disable_irq();
		if (block_ch4_1st == NULL) {
			block_ch4_1st = block;
			ch4_offset = 0;
			__enable_irq();
		} else if (block_ch4_2nd == NULL) {
			block_ch4_2nd = block;
			__enable_irq();
		} else {
			tmp = block_ch4_1st;
			block_ch4_1st = block_ch4_2nd;
			block_ch4_2nd = block;
			ch4_offset = 0;
			__enable_irq();
			release(tmp);
		}
	}
	block = receiveReadOnly(4); // channel 5
	if (block) {
		__disable_irq();
		if (block_ch5_1st == NULL) {
			block_ch5_1st = block;
			ch5_offset = 0;
			__enable_irq();
		} else if (block_ch5_2nd == NULL) {
			block_ch5_2nd = block;
			__enable_irq();
		} else {
			tmp = block_ch5_1st;
			block_ch5_1st = block_ch5_2nd;
			block_ch5_2nd = block;
			ch5_offset = 0;
			__enable_irq();
			release(tmp);
		}
	}
	block = receiveReadOnly(5); // channel 6
	if (block) {
		__disable_irq();
		if (block_ch6_1st == NULL) {
			block_ch6_1st = block;
			ch6_offset = 0;
			__enable_irq();
		} else if (block_ch6_2nd == NULL) {
			block_ch6_2nd = block;
			__enable_irq();
		} else {
			tmp = block_ch6_1st;
			block_ch6_1st = block_ch6_2nd;
			block_ch6_2nd = block;
			ch6_offset = 0;
			__enable_irq();
			release(tmp);
		}
	}
	block = receiveReadOnly(6); // channel 7
	if (block) {
		__disable_irq();
		if (block_ch7_1st == NULL) {
			block_ch7_1st = block;
			ch7_offset = 0;
			__enable_irq();
		} else if (block_ch7_2nd == NULL) {
			block_ch7_2nd = block;
			__enable_irq();
		} else {
			tmp = block_ch7_1st;
			block_ch7_1st = block_ch7_2nd;
			block_ch7_2nd = block;
			ch7_offset = 0;
			__enable_irq();
			release(tmp);
		}
	}
	block = receiveReadOnly(7); // channel 8
	if (block) {
		__disable_irq();
		if (block_ch8_1st == NULL) {
			block_ch8_1st = block;
			ch8_offset = 0;
			__enable_irq();
		} else if (block_ch8_2nd == NULL) {
			block_ch8_2nd = block;
			__enable_irq();
		} else {
			tmp = block_ch8_1st;
			block_ch8_1st = block_ch8_2nd;
			block_ch8_2nd = block;
			ch8_offset = 0;
			__enable_irq();
			release(tmp);
		}
	}
}


#if defined(KINETISK)
#if F_CPU == 96000000 || F_CPU == 48000000 || F_CPU == 24000000
  // PLL is at 96 MHz in these modes
  #define MCLK_MULT 2
  #define MCLK_DIV  17
#elif F_CPU == 72000000
  #define MCLK_MULT 8
  #define MCLK_DIV  51
#elif F_CPU == 120000000
  #define MCLK_MULT 8
  #define MCLK_DIV  85
#elif F_CPU == 144000000
  #define MCLK_MULT 4
  #define MCLK_DIV  51
#elif F_CPU == 168000000
  #define MCLK_MULT 8
  #define MCLK_DIV  119
#elif F_CPU == 180000000
  #define MCLK_MULT 16
  #define MCLK_DIV  255
  #define MCLK_SRC  0
#elif F_CPU == 192000000
  #define MCLK_MULT 1
  #define MCLK_DIV  17
#elif F_CPU == 216000000
  #define MCLK_MULT 12
  #define MCLK_DIV  17
  #define MCLK_SRC  1
#elif F_CPU == 240000000
  #define MCLK_MULT 2
  #define MCLK_DIV  85
  #define MCLK_SRC  0
#elif F_CPU == 256000000
  #define MCLK_MULT 12
  #define MCLK_DIV  17
  #define MCLK_SRC  1
#elif F_CPU == 16000000
  #define MCLK_MULT 12
  #define MCLK_DIV  17
#else
  #error "This CPU Clock Speed is not supported by the Audio library";
#endif

#ifndef MCLK_SRC
#if F_CPU >= 20000000
  #define MCLK_SRC  3  // the PLL
#else
  #define MCLK_SRC  0  // system clock
#endif
#endif
#endif

PROGMEM
void AudioOutputADAT::config_ADAT(void)
{
#if defined(KINETISK)
	SIM_SCGC6 |= SIM_SCGC6_I2S;
	SIM_SCGC7 |= SIM_SCGC7_DMA;
	SIM_SCGC6 |= SIM_SCGC6_DMAMUX;

	// enable MCLK output
	I2S0_MCR = I2S_MCR_MICS(MCLK_SRC) | I2S_MCR_MOE;
	//while (I2S0_MCR & I2S_MCR_DUF) ;
	//I2S0_MDR = I2S_MDR_FRACT((MCLK_MULT-1)) | I2S_MDR_DIVIDE((MCLK_DIV-1));

	AudioOutputADAT::setI2SFreq(88200);

	// configure transmitter
	I2S0_TMR = 0;
	I2S0_TCR1 = I2S_TCR1_TFW(1);  // watermark
	I2S0_TCR2 = I2S_TCR2_SYNC(0) | I2S_TCR2_MSEL(1) | I2S_TCR2_BCD | I2S_TCR2_DIV(0);
	I2S0_TCR3 = I2S_TCR3_TCE;

	//8 Words per Frame 32 Bit Word-Length -> 256 Bit Frame-Length, MSB First:
	I2S0_TCR4 = I2S_TCR4_FRSZ(7) | I2S_TCR4_SYWD(0) | I2S_TCR4_MF | I2S_TCR4_FSP | I2S_TCR4_FSD;
	I2S0_TCR5 = I2S_TCR5_WNW(31) | I2S_TCR5_W0W(31) | I2S_TCR5_FBT(31);

	I2S0_RCSR = 0;

#if 0
	// configure pin mux for 3 clock signals (debug only)
	CORE_PIN23_CONFIG = PORT_PCR_MUX(6); // pin 23, PTC2, I2S0_TX_FS (LRCLK)	44.1kHz
	CORE_PIN9_CONFIG  = PORT_PCR_MUX(6); // pin  9, PTC3, I2S0_TX_BCLK		5.6 MHz
	CORE_PIN11_CONFIG = PORT_PCR_MUX(6); // pin 11, PTC6, I2S0_MCLK			11.43MHz
#endif

#elif defined(__IMXRT1052__) || defined(__IMXRT1062__)
    
    

	CCM_CCGR5 |= CCM_CCGR5_SAI1(CCM_CCGR_ON);
    
    // if either transmitter or receiver is enabled, do nothing /AAA from output_i2s
	if (I2S1_TCSR & I2S_TCSR_TE) return;
	if (I2S1_RCSR & I2S_RCSR_RE) return;
    
//PLL:
	int fs = AUDIO_SAMPLE_RATE_EXACT;
	// PLL between 27*24 = 648MHz und 54*24=1296MHz
	int n1 = 4; //SAI prescaler 4 => (n1*n2) = multiple of 4
	int n2 = 1 + (24000000 * 27) / (fs * 256 * n1);

	double C = ((double)fs * 256 * n1 * n2) / 24000000;
	int c0 = C;
	int c2 = 10000;
	int c1 = C * c2 - (c0 * c2);
	set_audioClock(c0, c1, c2);

	CCM_CSCMR1 = (CCM_CSCMR1 & ~(CCM_CSCMR1_SAI1_CLK_SEL_MASK))
		   | CCM_CSCMR1_SAI1_CLK_SEL(2); // &0x03 // (0,1,2): PLL3PFD0, PLL5, PLL4
	CCM_CS1CDR = (CCM_CS1CDR & ~(CCM_CS1CDR_SAI1_CLK_PRED_MASK | CCM_CS1CDR_SAI1_CLK_PODF_MASK))
		   | CCM_CS1CDR_SAI1_CLK_PRED(n1-1) // &0x07
		   | CCM_CS1CDR_SAI1_CLK_PODF(n2-1); // &0x3f
    
    //Select MCLK
	IOMUXC_GPR_GPR1 = (IOMUXC_GPR_GPR1 & ~(IOMUXC_GPR_GPR1_SAI1_MCLK1_SEL_MASK))
			| (IOMUXC_GPR_GPR1_SAI1_MCLK_DIR | IOMUXC_GPR_GPR1_SAI1_MCLK1_SEL(0));	

	int rsync = 0;
	int tsync = 1;
    
	// configure transmitter
	I2S1_TMR = 0;
	I2S1_TCR1 = I2S_TCR1_RFW(0);  // watermark
	I2S1_TCR2 = I2S_TCR2_SYNC(tsync) | I2S_TCR2_MSEL(1) | I2S_TCR2_BCD | I2S_TCR2_DIV(0);
	I2S1_TCR3 = I2S_TCR3_TCE;

	// fix..4 Words per Frame 32 Bit Word-Length -> 128 Bit Frame-Length, MSB First:
    // i want.. 8 Words per Frame 32 Bit Word-Length -> 256 Bit Frame-Length, MSB First:
	I2S1_TCR4 = I2S_TCR4_FRSZ(7) | I2S_TCR4_SYWD(0) | I2S_TCR4_MF | I2S_TCR4_FSP | I2S_TCR4_FSD;
	I2S1_TCR5 = I2S_TCR5_WNW(31) | I2S_TCR5_W0W(31) | I2S_TCR5_FBT(31);
    
    //8 Words per Frame 32 Bit Word-Length -> 256 Bit Frame-Length, MSB First:
	//I2S0_TCR4 = I2S_TCR4_FRSZ(7) | I2S_TCR4_SYWD(0) | I2S_TCR4_MF | I2S_TCR4_FSP | //I2S_TCR4_FSD;
	//I2S0_TCR5 = I2S_TCR5_WNW(31) | I2S_TCR5_W0W(31) | I2S_TCR5_FBT(31);

	//I2S1_RCSR = 0;
	I2S1_RMR = 0;
	//I2S1_RCSR = (1<<25); //Reset
	I2S1_RCR1 = I2S_RCR1_RFW(0);
	I2S1_RCR2 = I2S_RCR2_SYNC(rsync) | I2S_TCR2_MSEL(1) | I2S_TCR2_BCD | I2S_TCR2_DIV(0);
	I2S1_RCR3 = I2S_RCR3_RCE;
	I2S1_RCR4 = I2S_TCR4_FRSZ(3) | I2S_TCR4_SYWD(0) | I2S_TCR4_MF | I2S_TCR4_FSP | I2S_TCR4_FSD;
	I2S1_RCR5 = I2S_TCR5_WNW(31) | I2S_TCR5_W0W(31) | I2S_TCR5_FBT(31);
    
    //AudioOutputADAT::setI2SFreq(88200);

#if 0
	//debug only:
	CORE_PIN23_CONFIG = 3;  //1:MCLK	11.43MHz
	CORE_PIN21_CONFIG = 3;  //1:RX_BCLK	5.6 MHz
	CORE_PIN20_CONFIG = 3;  //1:RX_SYNC	44.1 KHz
//	CORE_PIN6_CONFIG  = 3;  //1:TX_DATA0
//	CORE_PIN7_CONFIG  = 3;  //1:RX_DATA0
#endif

#endif
}

/*

https://forum.pjrc.com/threads/38753-Discussion-about-a-simple-way-to-change-the-sample-rate

*/



void AudioOutputADAT::setI2SFreq(int freq) {
     // PLL between 27*24 = 648MHz und 54*24=1296MHz
  int n1 = 4; //SAI prescaler 4 => (n1*n2) = multiple of 4
  int n2 = 1 + (24000000 * 27) / (freq * 256 * n1);
  double C = ((double)freq * 256 * n1 * n2) / 24000000;
  int c0 = C;
  int c2 = 10000;
  int c1 = C * c2 - (c0 * c2);
  set_audioClock(c0, c1, c2, true);
  CCM_CS1CDR = (CCM_CS1CDR & ~(CCM_CS1CDR_SAI1_CLK_PRED_MASK | CCM_CS1CDR_SAI1_CLK_PODF_MASK))
       | CCM_CS1CDR_SAI1_CLK_PRED(n1-1) // &0x07
       | CCM_CS1CDR_SAI1_CLK_PODF(n2-1); // &0x3f 
//Serial.printf("SetI2SFreq(%d)\n",freq);
} 

#elif defined(KINETISL)

void AudioOutputADAT::update(void)
{

	audio_block_t *block;
	block = receiveReadOnly(0); // input 0 = ch1 channel
	if (block) release(block);
	block = receiveReadOnly(1); // input 1 = ch2 channel
	if (block) release(block);
	block = receiveReadOnly(2); // input 2 = ch3 channel
	if (block) release(block);
	block = receiveReadOnly(3); // input 3 = ch4 channel
	if (block) release(block);
	block = receiveReadOnly(4); // input 4 = ch5 channel
	if (block) release(block);
	block = receiveReadOnly(5); // input 5 = ch6 channel
	if (block) release(block);
	block = receiveReadOnly(6); // input 6 = ch7 channel
	if (block) release(block);
	block = receiveReadOnly(7); // input 7 = ch8 channel
	if (block) release(block);
}

#endif

Can you suggest anything at this point? I am out of ideas.

edit: I also tried this code from output_spdif..

Code:
	#if IMXRT_CACHE_ENABLED >= 2
	dest -= AUDIO_BLOCK_SAMPLES * 4/2 + 4/2;
	arm_dcache_flush_delete(dest, sizeof(SPDIF_tx_buffer) / 2 );
	#endif

It looks like you didn't set the correct sample rate, according to the original output_adat the sample rate has to be double, what you copied from output_i2s is:
Code:
int fs = AUDIO_SAMPLE_RATE_EXACT;
//AUDIO_SAMPLE_RATE_EXACT = 44100
Try setting it to 88200 and see what happens.
 
Oh my days.. thanks for that vjmuzik. I now have something that resembles audio! wow. it is still very roboty though. I must have copied across some other mistakes as well : /

is there anything else that is obvious?
 
with the ADAT_DrumSamplePlayer I am now getting 5 channels of very distorted audio. I should be getting 7 but its a result for sure!

In the orig code you just highlighted to me it says:

"Because BITCLK can not be the same as MCLK, but only half of MCLK, we need a 2*MCLK (so for 44100 samplerate we need 88200 MCLK)"

using "AUDIO_SAMPLE_RATE_EXACT = 44100" have I set both the BITCLK and MCLK to 882000?
 
A last hint for today:

in startup.c (in cores\tensy4\) you'll find these lines:
Code:
    SCB_MPU_RBAR = 0x20200000 | REGION(i++); // RAM (AXI bus)
    SCB_MPU_RASR = MEM_CACHE_WBWA | READWRITE | NOEXEC | SIZE_1M;
For a test - you can edit it the second line to
Code:
SCB_MPU_RASR = [COLOR=#ff0000]MEM_CACHE_WT[/COLOR] | READWRITE | NOEXEC | SIZE_1M;
This enables cache write-though
So.. you can check if your lines in the code re: cache-handling are correct.
If it sounds different now, your code is not correct.

It is important to get this right before looking for other problems.

Good night.

I have just spotted this post! Ta Frank. I will try this now and see if it is the missing bit of the puzzle..
 
Thanks so much for the help with this gents. I genuinely can't believe it's working!

two questions...

how can I get it working without the modification to startup.c

and also in this code....

Code:
	//I2S1_RCSR = 0;
	I2S1_RMR = 0;
	//I2S1_RCSR = (1<<25); //Reset
	I2S1_RCR1 = I2S_RCR1_RFW(0);
	I2S1_RCR2 = I2S_RCR2_SYNC(rsync) | I2S_TCR2_MSEL(1) | I2S_TCR2_BCD | I2S_TCR2_DIV(0);
	I2S1_RCR3 = I2S_RCR3_RCE;
	I2S1_RCR4 = I2S_TCR4_FRSZ(3) | I2S_TCR4_SYWD(0) | I2S_TCR4_MF | I2S_TCR4_FSP | I2S_TCR4_FSD;
	I2S1_RCR5 = I2S_TCR5_WNW(31) | I2S_TCR5_W0W(31) | I2S_TCR5_FBT(31);

I2S_TCR4_FRSZ(3) should this be set to 7 as it is in the lines of code above it?

Code:
    // i want.. 8 Words per Frame 32 Bit Word-Length -> 256 Bit Frame-Length, MSB First:
	I2S1_TCR4 = I2S_TCR4_FRSZ(7) | I2S_TCR4_SYWD(0) | I2S_TCR4_MF | I2S_TCR4_FSP | I2S_TCR4_FSD;
	I2S1_TCR5 = I2S_TCR5_WNW(31) | I2S_TCR5_W0W(31) | I2S_TCR5_FBT(31);

This line of code was taken from the spdif output code as it wasn't present in the orig adat output code.
 
how can I get it working without the modification to startup.c

Try adding this near the beginning of the isr() function, just after the if-else where "dest" and "end" are set.

Code:
    uint32_t *dest_orig = dest;

Then at the end of isr(), change the cache function to use dest_orig.

Code:
    arm_dcache_flush_delete(dest_orig, sizeof(ADAT_tx_buffer) / 2 );
 
Or maybe try changing that last line of isr() to this, which would avoid the need to add the "dest_orig" variable near the beginning.

Code:
    arm_dcache_flush_delete((void *)((uint32_t)dest - sizeof(ADAT_tx_buffer) / 2), sizeof(ADAT_tx_buffer) / 2 );
 
Or maybe try changing that last line of isr() to this, which would avoid the need to add the "dest_orig" variable near the beginning.

Code:
    arm_dcache_flush_delete((void *)((uint32_t)dest - sizeof(ADAT_tx_buffer) / 2), sizeof(ADAT_tx_buffer) / 2 );

That has fixed that problem completely! now working without any modification to startup.c

what should I do about the code below?

Code:
	// configure transmitter
	I2S1_TMR = 0;
	I2S1_TCR1 = I2S_TCR1_RFW(0);  // watermark
	I2S1_TCR2 = I2S_TCR2_SYNC(tsync) | I2S_TCR2_MSEL(1) | I2S_TCR2_BCD | I2S_TCR2_DIV(0);
	I2S1_TCR3 = I2S_TCR3_TCE;

    // i want.. 8 Words per Frame 32 Bit Word-Length -> 256 Bit Frame-Length, MSB First:
	I2S1_TCR4 = I2S_TCR4_FRSZ(7) | I2S_TCR4_SYWD(0) | I2S_TCR4_MF | I2S_TCR4_FSP | I2S_TCR4_FSD;
	I2S1_TCR5 = I2S_TCR5_WNW(31) | I2S_TCR5_W0W(31) | I2S_TCR5_FBT(31);

	//I2S1_RCSR = 0;
	I2S1_RMR = 0;
	//I2S1_RCSR = (1<<25); //Reset
	I2S1_RCR1 = I2S_RCR1_RFW(0);
    
    // should this be I2S_TCR4_FRSZ(7) as above? both 3 and 7 work in both places
	I2S1_RCR2 = I2S_RCR2_SYNC(rsync) | I2S_TCR2_MSEL(1) | I2S_TCR2_BCD | I2S_TCR2_DIV(0);
	I2S1_RCR3 = I2S_RCR3_RCE;
	I2S1_RCR4 = I2S_TCR4_FRSZ(3) | I2S_TCR4_SYWD(0) | I2S_TCR4_MF | I2S_TCR4_FSP | I2S_TCR4_FSD;
	I2S1_RCR5 = I2S_TCR5_WNW(31) | I2S_TCR5_W0W(31) | I2S_TCR5_FBT(31);

should it be I2S_TCR4_FRSZ(7) or I2S_TCR4_FRSZ(3)? both 3 and 7 seem to work in both places
 
I'd say, if both works leave it as a comment in the code and use the value you are using now.
After that, make a pull-request on github so that Paul can merge it- :)

Thank you very much for fixing this.
 
I am literally bouncing off the walls right now!

You are welcome. I cant wait to put it to use. having this kind of quality output on such a small platform is a massive game changer for live audio applications. I can ditch Ableton live and 2x macbook pros (redundancy) for two of these!

I have deffo broken output_adat.cpp for use on Teensy 3.X and I don't have a T3 to see if I can fix it. I doubt you want this merged as it will break for anyone using it on T3. What is the best way to proceed?
 
What is the best way to proceed?

If you're able to use git, send a pull request.

If not, don't worry. Just put the final known-good code in a post here on the forum and I'll manually merge it. Just make sure it's the exact file, since I don't have any ADAT gear to check if it's really working.
 
what is the purpose of I2S1_TCR4 and I2S1_RCR4 ? If I know that I can probably work out if they should be equal to I2S_TCR4_FRSZ(3) or I2S_TCR4_FRSZ(7)
 
If you're able to use git, send a pull request.

If not, don't worry. Just put the final known-good code in a post here on the forum and I'll manually merge it. Just make sure it's the exact file, since I don't have any ADAT gear to check if it's really working.

Will this not break the code for Teensy 3.X people? I removed "void AudioOutputADAT::setI2SFreq(int freq)" from output_adat.cpp as it was stopping the code from compiling (I should have fixed it properly but I honestly wasn't expecting to get this working)
 
Will this not break the code for Teensy 3.X people?

It might. If you're willing to test and prepare code that works on both, I could send you a Teensy 3.2.


Also, if you're willing to do a bit more, there are 3 things which could really help everyone needing ADAT in the future.

1: A known-good test program for all 8 channels for the examples > HardwareTesting folder would be awesome. We already have the ADAT_DrumSamplePlayer from Ernstjan Freriks who created the original ADAT code. It seems to send to 7 of the 8 channels. Another example which can be used for testing all 8 would be good.

2: Any photos, video, and specific info about the parts and materials used to connect Teensy 4.0 to ADAT gear could really help other people in the future to use this.

3: If you're willing to have your contact info (email, social media, etc) in the code, when issues come up in the distant future, hopefully we'll be able to contact you. For specialty stuff like ADAT where Frank and I and others lack the hardware, we really depend on having contact with people who can confirm whether it's really working.
 
Back
Top