ADAT (Alesis Digital Audio Tape) interface codec using STM32F411RE Nucleo board. ADAT frame encoding / decoding rate is ~113000 frames/s, faster than real-time needs (48000 frames/s) Future work will attempt to implement an 8-in / 8-out digital mixer using DMA SPI Rx+Tx with a behringer ada8200.
main.cpp
00001 // MCU ADAT frames encoding (proof of concept) 00002 // 8 24-bit audio data -> 8 32-bit NRZI encoded ADAT frames 00003 // 480000 ADAT frames are encoded within ~3s, so encoding should require 30% CPU time (STM32F411RE) 00004 // This might leave margin for: 00005 // ADAT decoding (NRZI decoding is less CPU intensive) 00006 // Audio mixing 8 in -> 8 out 00007 // Rx SPI w/ DMA 00008 // Tx SPI w/ DMA 00009 // 00010 // Encoding is fully unrolled (faster?), starting from last frame bits so that the compiler can make use of ROR instruction (does it?) 00011 // NOT TESTED with ADAT device 00012 // Result is displayed on terminal 00013 00014 #include "mbed.h" 00015 #include "mbprt.h" 00016 #include <sstream> 00017 00018 Timer t; 00019 00020 // NRZI encoding LUT 00021 char lut[256] = {0x0, 0xff, 0xfe, 0x1, 0xfc, 0x3, 0x2, 0xfd, 0xf8, 0x7, 0x6, 0xf9, 0x4, 0xfb, 0xfa, 0x5, 00022 0xf0, 0xf, 0xe, 0xf1, 0xc, 0xf3, 0xf2, 0xd, 0x8, 0xf7, 0xf6, 0x9, 0xf4, 0xb, 0xa, 0xf5, 00023 0xe0, 0x1f, 0x1e, 0xe1, 0x1c, 0xe3, 0xe2, 0x1d, 0x18, 0xe7, 0xe6, 0x19, 0xe4, 0x1b, 0x1a, 0xe5, 00024 0x10, 0xef, 0xee, 0x11, 0xec, 0x13, 0x12, 0xed, 0xe8, 0x17, 0x16, 0xe9, 0x14, 0xeb, 0xea, 0x15, 00025 0xc0, 0x3f, 0x3e, 0xc1, 0x3c, 0xc3, 0xc2, 0x3d, 0x38, 0xc7, 0xc6, 0x39, 0xc4, 0x3b, 0x3a, 0xc5, 00026 0x30, 0xcf, 0xce, 0x31, 0xcc, 0x33, 0x32, 0xcd, 0xc8, 0x37, 0x36, 0xc9, 0x34, 0xcb, 0xca, 0x35, 00027 0x20, 0xdf, 0xde, 0x21, 0xdc, 0x23, 0x22, 0xdd, 0xd8, 0x27, 0x26, 0xd9, 0x24, 0xdb, 0xda, 0x25, 00028 0xd0, 0x2f, 0x2e, 0xd1, 0x2c, 0xd3, 0xd2, 0x2d, 0x28, 0xd7, 0xd6, 0x29, 0xd4, 0x2b, 0x2a, 0xd5, 00029 0x80, 0x7f, 0x7e, 0x81, 0x7c, 0x83, 0x82, 0x7d, 0x78, 0x87, 0x86, 0x79, 0x84, 0x7b, 0x7a, 0x85, 00030 0x70, 0x8f, 0x8e, 0x71, 0x8c, 0x73, 0x72, 0x8d, 0x88, 0x77, 0x76, 0x89, 0x74, 0x8b, 0x8a, 0x75, 00031 0x60, 0x9f, 0x9e, 0x61, 0x9c, 0x63, 0x62, 0x9d, 0x98, 0x67, 0x66, 0x99, 0x64, 0x9b, 0x9a, 0x65, 00032 0x90, 0x6f, 0x6e, 0x91, 0x6c, 0x93, 0x92, 0x6d, 0x68, 0x97, 0x96, 0x69, 0x94, 0x6b, 0x6a, 0x95, 00033 0x40, 0xbf, 0xbe, 0x41, 0xbc, 0x43, 0x42, 0xbd, 0xb8, 0x47, 0x46, 0xb9, 0x44, 0xbb, 0xba, 0x45, 00034 0xb0, 0x4f, 0x4e, 0xb1, 0x4c, 0xb3, 0xb2, 0x4d, 0x48, 0xb7, 0xb6, 0x49, 0xb4, 0x4b, 0x4a, 0xb5, 00035 0xa0, 0x5f, 0x5e, 0xa1, 0x5c, 0xa3, 0xa2, 0x5d, 0x58, 0xa7, 0xa6, 0x59, 0xa4, 0x5b, 0x5a, 0xa5, 00036 0x50, 0xaf, 0xae, 0x51, 0xac, 0x53, 0x52, 0xad, 0xa8, 0x57, 0x56, 0xa9, 0x54, 0xab, 0xaa, 0x55}; 00037 00038 uint32_t data[8]; // 24-bit audio in 00039 uint32_t adat[8]; // raw ADAT frame 00040 uint32_t adat_nrz[8]; // NRZI encoded ADAT frame 00041 uint32_t dec_nrz[8]; // NRZI decoded ADAT frame 00042 uint32_t adec[8]; // audio decoded frame 00043 00044 DigitalIn pb(USER_BUTTON); 00045 DigitalOut myled(LED1); 00046 00047 // To display 32-bit binary data 00048 const char *byte_to_binary(int x) 00049 { 00050 static char b[33]; 00051 b[32] = '\0'; 00052 00053 int z; 00054 for (z=0;z<32;z++) 00055 { 00056 b[z] = 48 + ( (x & (1<<(31-z))) != 0); 00057 } 00058 00059 return b; 00060 } 00061 00062 00063 // Right rotation 00064 inline uint32_t rorn (uint32_t x, uint32_t n) 00065 { 00066 return ((x)>>n) | ((x)<<(32-n)); 00067 } 00068 00069 // 1-bit right rotation 00070 inline void ror1(uint32_t* x) 00071 { 00072 *x = ((*x)>>1) | ((*x)<<(31)); 00073 } 00074 00075 00076 inline uint32_t adat2audio(uint32_t x) 00077 { 00078 00079 uint32_t R = x&0xF; 00080 R |= ( (x>>1) & 0xF0); 00081 R |= ( (x>>2) & 0xF00); 00082 R |= ( (x>>3) & 0xF000); 00083 R |= ( (x>>4) & 0xF0000); 00084 R |= ( (x>>5) & 0xF00000); 00085 00086 return R; 00087 } 00088 00089 inline uint32_t audio2adat(uint32_t x) 00090 { 00091 uint32_t R = 0x02108421; 00092 R |= ( (x << 1) & 0x1E ); 00093 R |= ( (x << 2) & 0x3c0 ); 00094 R |= ( (x << 3) & 0x7800 ); 00095 R |= ( (x << 4) & 0xf0000 ); 00096 R |= ( (x << 5) & 0x1E00000 ); 00097 R |= ( (x << 6) & 0x3c000000 ); 00098 return R; 00099 } 00100 00101 inline void adat_enc(uint32_t* in, uint32_t* out) 00102 { 00103 uint32_t R0, R1; 00104 R0 = audio2adat(in[0]); 00105 R1 = audio2adat(in[1]); 00106 out[0] = R0 | (R1 << 30); 00107 R0 = audio2adat(in[2]); 00108 out[1] = (R0 << 28) | (R1 >> 2); 00109 R1 = audio2adat(in[3]); 00110 out[2] = (R0 >> 4) | (R1 << 26); 00111 R0 = audio2adat(in[4]); 00112 out[3] = (R0 << 24) | (R1 >> 6); 00113 R1 = audio2adat(in[5]); 00114 out[4] = (R0 >> 8) | (R1 << 22); 00115 R0 = audio2adat(in[6]); 00116 out[5] = (R0 << 20) | (R1 >> 10); 00117 R1 = audio2adat(in[7]); 00118 out[6] = (R0 >> 12) | (R1 << 18); 00119 out[7] = 0x08010000 | (R1 >> 14); 00120 } 00121 00122 inline void adat_dec(uint32_t* in, uint32_t* out) 00123 { 00124 uint32_t R0, R1; 00125 R0 = in[0]; 00126 R1 = in[1]; 00127 out[0] = adat2audio(R0 >> 1); 00128 out[1] = adat2audio( (R0 >> 31) | (R1 << 1) ); 00129 R0 = in[2]; 00130 out[2] = adat2audio( (R1 >> 29) | (R0 << 3) ); 00131 R1 = in[3]; 00132 out[3] = adat2audio( (R0 >> 27) | (R1 << 5) ); 00133 R0 = in[4]; 00134 out[4] = adat2audio( (R1 >> 25) | (R0 << 7) ); 00135 R1 = in[5]; 00136 out[5] = adat2audio( (R0 >> 23) | (R1 << 9) ); 00137 R0 = in[6]; 00138 out[6] = adat2audio( (R1 >> 21) | (R0 << 11) ); 00139 R1 = in[7]; 00140 out[7] = adat2audio( (R0 >> 19) | (R1 << 13) ); 00141 } 00142 00143 00144 inline void nrz_enc(uint32_t* in, uint32_t* out) 00145 { 00146 static char last_bit = 0; 00147 for (int i = 0; i < 8; i++) 00148 { 00149 register uint32_t R = 0; 00150 uint32_t x = in[i]; 00151 unsigned char c; 00152 for (int j = 0; j < 4; j++) 00153 { 00154 c = lut[(unsigned char)(x >> (j*8))]; 00155 00156 c = last_bit ? ~c : c; 00157 last_bit = c >> 7; 00158 R = rorn(R | c, 8); 00159 } 00160 out[i] = R; 00161 } 00162 } 00163 00164 inline void nrz_dec(uint32_t* in, uint32_t* out) 00165 { 00166 static char dec_last_bit = 0; 00167 for (int i = 0; i < 8; i++) 00168 { 00169 uint32_t x = in[i]; 00170 out[i] = x ^ ( (x << 1) | dec_last_bit ); 00171 dec_last_bit = x >> 31; 00172 } 00173 } 00174 00175 00176 00177 00178 int main() { 00179 00180 Serial pc(USBTX, USBRX); 00181 pc.baud(115200); 00182 00183 for (int i = 0; i < 8; i++) 00184 { 00185 data[i] = 0x00042184 + (i << 20); 00186 } 00187 00188 uint32_t nframes = 480000; // 10s real time data 00189 gprintf("#VStarting encoding %Y ADAT frames\n", int(nframes)); 00190 t.start(); 00191 for (int j = 0; j < nframes; j++) 00192 { 00193 if (pb) // so that the compiler cannot preprocess anything 00194 { 00195 for (int i = 0; i < 8; i++) 00196 { 00197 data[i] = (data[i] - i) &0xffffff;//make it recursive (makes really sure the compiler won't attempt to preprocess anything) 00198 } 00199 00200 } 00201 myled = pb; 00202 00203 adat_enc(data, adat); 00204 nrz_enc(adat, adat_nrz); 00205 nrz_dec(adat_nrz, dec_nrz); 00206 adat_dec(dec_nrz, adec); 00207 } 00208 00209 00210 t.stop(); 00211 std::stringstream toto; 00212 toto << t.read(); 00213 gprintf("The time taken was %f seconds\n", toto.str()); 00214 for (int i = 0; i < 8; i++) 00215 { 00216 printf("data[%d] = %s\n", i, byte_to_binary(data[i])); 00217 } 00218 for (int i = 0; i < 8; i++) 00219 { 00220 printf("adat[%d] = %s\n", i, byte_to_binary(adat[i])); 00221 } 00222 for (int i = 0; i < 8; i++) 00223 { 00224 printf("adat_nrz[%d] = %s\n", i, byte_to_binary(adat_nrz[i])); 00225 } 00226 for (int i = 0; i < 8; i++) 00227 { 00228 printf("dec_nrz[%d] = %s\n", i, byte_to_binary(dec_nrz[i])); 00229 } 00230 for (int i = 0; i < 8; i++) 00231 { 00232 printf("adec[%d] = %s\n", i, byte_to_binary(adec[i])); 00233 } 00234 00235 00236 00237 00238 00239 } 00240 00241 00242
Generated on Sat Jul 16 2022 09:04:26 by 1.7.2