Hi, mon2. Thanks for your support. Well, I have new insights, I want to share. But, first I respond to your questions:
1.) I have test it. It doesn't make a difference.
2.) No problem. Here is the code:
Code: Select all
#pragma unsafe arrays
static inline void process_data(streaming chanend c_i2s,
in buffered port:32 p_wclk,
in buffered port:32 p_data[I2S_SLAVE_RX_COUNT_PORTS],
timer t,
unsigned transport_bit_width,
unsigned port_time,
unsigned low_sr,
unsigned high_sr) {
unsigned time, last_time;
unsigned pt;
unsigned data;
unsigned value;
unsigned right_channel = 0;
unsigned locked = 0;
unsigned wclk_pattern = 0x80000000;
unsigned xor_pattern = 0xffffffff << (32 - transport_bit_width);
// Calculating new port time
pt = port_time + transport_bit_width;
// Calculate new timeout
t :> time;
time += WCLK_WAIT_TIMEOUT;
while (true) {
[[ordered]]
select {
// When a word was received
case p_wclk @ pt :> value @ pt :
// Check sample rate
t :> time;
last_time = time;
unsigned duration = time - last_time;
if (time < last_time) duration += 0xffffffff;
if (locked > 1 && ((duration < low_sr) || (duration > high_sr))) {
log_error("Synchronization error. Sample rate has changed.");
return; // resync
} else {
locked++;
}
last_time = time;
// Calculate new timeout
time += WCLK_WAIT_TIMEOUT;
// Reading data from port
#pragma loop unroll
for (int i = 0; i < I2S_SLAVE_RX_COUNT_PORTS; i++) {
data = partin(p_data[i], transport_bit_width);
data = bitrev(data); // Incoming data is big endian, we swap it to have little endian
samples[i * 2 + right_channel] = data;
}
// Calculating new port time
pt += transport_bit_width;
// Validate word clock value
if (value != wclk_pattern) {
log_error("Synchronization error with word clock. (Is %u, %u expected)", value, wclk_pattern);
return; // resync
}
// Prepare wclk pattern for next cycle
wclk_pattern ^= xor_pattern;
break;
// When a timeout happens
case t when timerafter(time) :> void :
log_error("Synchronization error. Timeout reached.");
return; // resync
} // select
// Send data
if (right_channel) {
c_i2s <: I2S_DATA;
#pragma loop unroll
for (int i = 0; i < I2S_SLAVE_RX_COUNT_CHANNELS; i++) c_i2s <: samples[i];
}
right_channel = !right_channel;
} // while
}
I use "wclk_pattern" to verify, if I have read the sample correctly or not. If the pattern matches, the sample was successfully read. "wclk_pattern" has the 32 bit pattern "1000 0000 0000 0000 0000 0000 0000 0000", if it is the left channel, or it is inverted, if it is the right channel.
"log_error" is a own defined macro function that calls debug_printf dependent, which log level is configured for the lib.
3.) You are so right ;-). I must be tired, when I have wrote that.
4.) I haven't done it till now, because I have new insights. Maybe that the analyse of the assembler code is no more required. Mon2, don't hesitate to ask for it, if you think it is necessary despite my new insights.
Now and finally, I describe my new insights:
First, I tried to figure out, when the read error occurs. Therefore I add a counter var and output the number of iterations in the printf:
Code: Select all
// sync to the word clock
int counter = 0;
while (1) {
select {
case p_wclk @ pt :> value @ pt1 :
counter++;
// read data and do some other stuff
if (value != wclk_pattern) {
printf("value = %u, wclk_pattern = %u; pt1 = %u, pt = %u, counter: %u\n", value, wclk_pattern, pt1, pt, counter);
return;
}
break;
}
}
// do more stuff
The resulting output is interesting: 124 iterations at 48kHz and 249 at 96kHz. The number of iterations is stable and independent from the program start or i2s stream start. That means, the read error happens after nearly 1,3ms after entering the while loop. This may be an evidence, that the read error is not directly caused by the code above.
Then, I have reduced the code of my real project. The final version was only a thread for i2s reading and a dummy sample receiving thread without any processing or output and a thread for i2c for initializing the i2s hardware. That was less logic than the test project. In my test project, I additionally output the samples to spdif. Anyhow, even the reduced version of the real project has the read error. I haven't expect this result! Therefore, I replaced the code of the main.xc in my real project with the code from the test project. The problem doesn't occur any more! That means, that the workspace/build environment doesn't causes the problem. It must be anyhow the code. You may have seen in my lib list, I use lib_logging. I don't really use printf but debug_printf. I have added the following function to have a high-speed output per xscope:
Code: Select all
void xscope_user_init(void) {
xscope_register (0);
xscope_config_io(XSCOPE_IO_BASIC);
}
If I disable this functions with comments, then the read error doesn't occur anymore! That's surprising, because I use it also in my test project and there it works without any problems. Well, the problem is not solved yet, but I suppose, that the solution is near. It isn't solved, because I want to keep the xscope output. I don't understand, why the xscope output disturbs the timestamped reading -- up to now!