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
- Committer:
- graffou
- Date:
- 2019-01-06
- Revision:
- 2:79b8132da1d6
- Parent:
- 1:6349099b6962
File content as of revision 2:79b8132da1d6:
// MCU ADAT frames encoding (proof of concept) // 8 24-bit audio data -> 8 32-bit NRZI encoded ADAT frames // 480000 ADAT frames are encoded within ~3s, so encoding should require 30% CPU time (STM32F411RE) // This might leave margin for: // ADAT decoding (NRZI decoding is less CPU intensive) // Audio mixing 8 in -> 8 out // Rx SPI w/ DMA // Tx SPI w/ DMA // // Encoding is fully unrolled (faster?), starting from last frame bits so that the compiler can make use of ROR instruction (does it?) // NOT TESTED with ADAT device // Result is displayed on terminal #include "mbed.h" #include "mbprt.h" #include <sstream> Timer t; // NRZI encoding LUT char lut[256] = {0x0, 0xff, 0xfe, 0x1, 0xfc, 0x3, 0x2, 0xfd, 0xf8, 0x7, 0x6, 0xf9, 0x4, 0xfb, 0xfa, 0x5, 0xf0, 0xf, 0xe, 0xf1, 0xc, 0xf3, 0xf2, 0xd, 0x8, 0xf7, 0xf6, 0x9, 0xf4, 0xb, 0xa, 0xf5, 0xe0, 0x1f, 0x1e, 0xe1, 0x1c, 0xe3, 0xe2, 0x1d, 0x18, 0xe7, 0xe6, 0x19, 0xe4, 0x1b, 0x1a, 0xe5, 0x10, 0xef, 0xee, 0x11, 0xec, 0x13, 0x12, 0xed, 0xe8, 0x17, 0x16, 0xe9, 0x14, 0xeb, 0xea, 0x15, 0xc0, 0x3f, 0x3e, 0xc1, 0x3c, 0xc3, 0xc2, 0x3d, 0x38, 0xc7, 0xc6, 0x39, 0xc4, 0x3b, 0x3a, 0xc5, 0x30, 0xcf, 0xce, 0x31, 0xcc, 0x33, 0x32, 0xcd, 0xc8, 0x37, 0x36, 0xc9, 0x34, 0xcb, 0xca, 0x35, 0x20, 0xdf, 0xde, 0x21, 0xdc, 0x23, 0x22, 0xdd, 0xd8, 0x27, 0x26, 0xd9, 0x24, 0xdb, 0xda, 0x25, 0xd0, 0x2f, 0x2e, 0xd1, 0x2c, 0xd3, 0xd2, 0x2d, 0x28, 0xd7, 0xd6, 0x29, 0xd4, 0x2b, 0x2a, 0xd5, 0x80, 0x7f, 0x7e, 0x81, 0x7c, 0x83, 0x82, 0x7d, 0x78, 0x87, 0x86, 0x79, 0x84, 0x7b, 0x7a, 0x85, 0x70, 0x8f, 0x8e, 0x71, 0x8c, 0x73, 0x72, 0x8d, 0x88, 0x77, 0x76, 0x89, 0x74, 0x8b, 0x8a, 0x75, 0x60, 0x9f, 0x9e, 0x61, 0x9c, 0x63, 0x62, 0x9d, 0x98, 0x67, 0x66, 0x99, 0x64, 0x9b, 0x9a, 0x65, 0x90, 0x6f, 0x6e, 0x91, 0x6c, 0x93, 0x92, 0x6d, 0x68, 0x97, 0x96, 0x69, 0x94, 0x6b, 0x6a, 0x95, 0x40, 0xbf, 0xbe, 0x41, 0xbc, 0x43, 0x42, 0xbd, 0xb8, 0x47, 0x46, 0xb9, 0x44, 0xbb, 0xba, 0x45, 0xb0, 0x4f, 0x4e, 0xb1, 0x4c, 0xb3, 0xb2, 0x4d, 0x48, 0xb7, 0xb6, 0x49, 0xb4, 0x4b, 0x4a, 0xb5, 0xa0, 0x5f, 0x5e, 0xa1, 0x5c, 0xa3, 0xa2, 0x5d, 0x58, 0xa7, 0xa6, 0x59, 0xa4, 0x5b, 0x5a, 0xa5, 0x50, 0xaf, 0xae, 0x51, 0xac, 0x53, 0x52, 0xad, 0xa8, 0x57, 0x56, 0xa9, 0x54, 0xab, 0xaa, 0x55}; uint32_t data[8]; // 24-bit audio in uint32_t adat[8]; // raw ADAT frame uint32_t adat_nrz[8]; // NRZI encoded ADAT frame uint32_t dec_nrz[8]; // NRZI decoded ADAT frame uint32_t adec[8]; // audio decoded frame DigitalIn pb(USER_BUTTON); DigitalOut myled(LED1); // To display 32-bit binary data const char *byte_to_binary(int x) { static char b[33]; b[32] = '\0'; int z; for (z=0;z<32;z++) { b[z] = 48 + ( (x & (1<<(31-z))) != 0); } return b; } // Right rotation inline uint32_t rorn (uint32_t x, uint32_t n) { return ((x)>>n) | ((x)<<(32-n)); } // 1-bit right rotation inline void ror1(uint32_t* x) { *x = ((*x)>>1) | ((*x)<<(31)); } inline uint32_t adat2audio(uint32_t x) { uint32_t R = x&0xF; R |= ( (x>>1) & 0xF0); R |= ( (x>>2) & 0xF00); R |= ( (x>>3) & 0xF000); R |= ( (x>>4) & 0xF0000); R |= ( (x>>5) & 0xF00000); return R; } inline uint32_t audio2adat(uint32_t x) { uint32_t R = 0x02108421; R |= ( (x << 1) & 0x1E ); R |= ( (x << 2) & 0x3c0 ); R |= ( (x << 3) & 0x7800 ); R |= ( (x << 4) & 0xf0000 ); R |= ( (x << 5) & 0x1E00000 ); R |= ( (x << 6) & 0x3c000000 ); return R; } inline void adat_enc(uint32_t* in, uint32_t* out) { uint32_t R0, R1; R0 = audio2adat(in[0]); R1 = audio2adat(in[1]); out[0] = R0 | (R1 << 30); R0 = audio2adat(in[2]); out[1] = (R0 << 28) | (R1 >> 2); R1 = audio2adat(in[3]); out[2] = (R0 >> 4) | (R1 << 26); R0 = audio2adat(in[4]); out[3] = (R0 << 24) | (R1 >> 6); R1 = audio2adat(in[5]); out[4] = (R0 >> 8) | (R1 << 22); R0 = audio2adat(in[6]); out[5] = (R0 << 20) | (R1 >> 10); R1 = audio2adat(in[7]); out[6] = (R0 >> 12) | (R1 << 18); out[7] = 0x08010000 | (R1 >> 14); } inline void adat_dec(uint32_t* in, uint32_t* out) { uint32_t R0, R1; R0 = in[0]; R1 = in[1]; out[0] = adat2audio(R0 >> 1); out[1] = adat2audio( (R0 >> 31) | (R1 << 1) ); R0 = in[2]; out[2] = adat2audio( (R1 >> 29) | (R0 << 3) ); R1 = in[3]; out[3] = adat2audio( (R0 >> 27) | (R1 << 5) ); R0 = in[4]; out[4] = adat2audio( (R1 >> 25) | (R0 << 7) ); R1 = in[5]; out[5] = adat2audio( (R0 >> 23) | (R1 << 9) ); R0 = in[6]; out[6] = adat2audio( (R1 >> 21) | (R0 << 11) ); R1 = in[7]; out[7] = adat2audio( (R0 >> 19) | (R1 << 13) ); } inline void nrz_enc(uint32_t* in, uint32_t* out) { static char last_bit = 0; for (int i = 0; i < 8; i++) { register uint32_t R = 0; uint32_t x = in[i]; unsigned char c; for (int j = 0; j < 4; j++) { c = lut[(unsigned char)(x >> (j*8))]; c = last_bit ? ~c : c; last_bit = c >> 7; R = rorn(R | c, 8); } out[i] = R; } } inline void nrz_dec(uint32_t* in, uint32_t* out) { static char dec_last_bit = 0; for (int i = 0; i < 8; i++) { uint32_t x = in[i]; out[i] = x ^ ( (x << 1) | dec_last_bit ); dec_last_bit = x >> 31; } } int main() { Serial pc(USBTX, USBRX); pc.baud(115200); for (int i = 0; i < 8; i++) { data[i] = 0x00042184 + (i << 20); } uint32_t nframes = 480000; // 10s real time data gprintf("#VStarting encoding %Y ADAT frames\n", int(nframes)); t.start(); for (int j = 0; j < nframes; j++) { if (pb) // so that the compiler cannot preprocess anything { for (int i = 0; i < 8; i++) { data[i] = (data[i] - i) &0xffffff;//make it recursive (makes really sure the compiler won't attempt to preprocess anything) } } myled = pb; adat_enc(data, adat); nrz_enc(adat, adat_nrz); nrz_dec(adat_nrz, dec_nrz); adat_dec(dec_nrz, adec); } t.stop(); std::stringstream toto; toto << t.read(); gprintf("The time taken was %f seconds\n", toto.str()); for (int i = 0; i < 8; i++) { printf("data[%d] = %s\n", i, byte_to_binary(data[i])); } for (int i = 0; i < 8; i++) { printf("adat[%d] = %s\n", i, byte_to_binary(adat[i])); } for (int i = 0; i < 8; i++) { printf("adat_nrz[%d] = %s\n", i, byte_to_binary(adat_nrz[i])); } for (int i = 0; i < 8; i++) { printf("dec_nrz[%d] = %s\n", i, byte_to_binary(dec_nrz[i])); } for (int i = 0; i < 8; i++) { printf("adec[%d] = %s\n", i, byte_to_binary(adec[i])); } }