Open 0xFACE opened 11 years ago
Thank you for reporting this. That is really an open issue.
The background: Inside the I2S module of the BCM2708 there is a register flag that can be used to wait for 2 clock cycles. It is used to wait for the FIFO to be cleared.
The corresponding code is here: https://github.com/koalo/linux/blob/rpi-3.8.y-asocdev/sound/soc/bcm2708/bcm2708-i2s.c#L251
However, this doesn't work so the loop runs into a timeout. This is not really a problem, because this timeout is long enough, but it is bad style. I have no idea what is wrong, but maybe we can find someone how knows how this should work (maybe someone from Broadcom).
Datasheet says that the interface must be enabled (BCM2708_I2S_EN = 1), but to modify regs not running (BCM2708_I2S_TXON = 0 and BCM2708_I2S_RXON = 0) and some clock running to wait for (wait for 2 PCM clocks). In the current implementation the first condition is not true. As for the second this a bit more complex from my understanding. Internal I2S logic needs a clock to move bits around (clearing the FIFO). In master mode this will be the PCM_CLK but in slave mode this is the bitclock supplied by the codec even if the I2S interface is not running. At least for master mode I think this is not happening either, because bcm2708_i2s_prepare is called before bcm2708_i2s_start where the clock is started.
I thought "not running" also means EN=0, but you are right: In section "Software Operation" they set the EN bit at the beginning. The running clock is a really good point, I didn't thought about that before... I will try this later.
I have tried it. The module is enabled before and the clock is started, but the error still remains.
I have to disagree. This https://github.com/koalo/linux/blob/rpi-3.8.y-asocdev/sound/soc/bcm2708/bcm2708-i2s.c#L268 is wrong. And I also think that clearing FIFOs should be done per stream to not disrupt first one when the second is opened. Another thing that must be checked is for the case that bcm2708 i2s interface is running in slave mode and at the time that fifos are cleared the codec is supplying the bitclock.From what I found for the WM8731 proto in master mode this doesn't happens, there is no bitclock at that time.The error is gone if you switch to slave mode for the WM8731 proto in the machine driver(SND_SOC_DAIFMT_CBS_CFS).So maybe there is a better place to clear the fifos somewhere where the bitclock from the codec is present when bcm2708 i2s interface is running in slave mode.
This ... is wrong.
I am so stupid - thank you very much!
And I also think that clearing FIFOs should be done per stream to not disrupt first one when the second is opened.
You are right, but is it legal to use the SYNC while one of the streams is running? Otherwise I have to disrupt the other stream - and that might introduce problems with channel swapping if the FIFO is not cleared (this is at least what I discovered during testing).
So maybe there is a better place to clear the fifos somewhere where the bitclock from the codec is present when bcm2708 i2s interface is running in slave mode.
I will have a look at it. Maybe it is necessary to provide a clock even in slave mode (at least for clearing the FIFOs).
And yes you are also right that wont work (the interface will be running). Ideally would be nice to reset the fifos every time when we start a stream but if full duplex support is a must this cant be done.The other approach would be to reset both fifos when the interface is configured like in bcm2708_i2s_hw_params briefly supplying the clock as you suggested (as the bcm2708 is the bitclock master for a short period) but I am not sure what the codec state would be at that time and that would be safe(two outputs tied together).I have already tested that and seems to work but then again I don't know how safe will be.
if full duplex support is a must
I am sorry, but it is for my application
but I am not sure what the codec state would be at that time
The big problem with this is, that it the order in which the callbacks from different streams are called is not defined. Therefore, one can not assume anything about the state of the other stream. When e.g. hw_params is called, the second stream could be not existing, after hw_params, after prepare, running... This also applies for the codec. We could look into the ASoC core, but as it does not seem defined, it could be changed at any time.
Why do you think, that hw_params is better? According to https://www.kernel.org/doc/htmldocs/writing-an-alsa-driver.html#pcm-interface-operators-prepare-callback the only difference is, that prepare is also called after an overrun, so for me it seems better to have it in prepare.
I am not saying that fullduplex is wrong.I also prefer that to have this functionality. The only reason was that I placed it after this https://github.com/koalo/linux/blob/rpi-3.8.y-asocdev/sound/soc/bcm2708/bcm2708-i2s.c#L373 so was called only before the first stream and not when there is a running stream.
That is a good idea!
In order to handle this overrun issue: What do you think about checking if the FIFO is still empty (should be after hw_params when implemented as you proposed) in prepare? Only in case there is data in the FIFO (should be only after overrun) we halt both streams, clear both FIFOs and start again?
I think this is good point.It will be keeping the hardware in sync especially for 32 bit samples.I will test that.
I implemented this with c1062523fed46bb5bb649b44be9a72421511e0a5 For master mode it works, finally! For slave mode it does not work :-( Do you have temporarily activated master mode?
Sorry for silly question. What you mean "Master mode"? Is master mode when transmitter (Pi) as the master, has to generate the bit clock, word-select signal and data for the DAC? I have TDA1543 connected to Pi and now I2S SYNC error gone away. So I think this is master mode ;-)
Is master mode when transmitter (Pi) as the master, has to generate the bit clock, word-select signal and data for the DAC?
Exactly! At least for this special case :-)
Does this issue still exist in 3.10?
Every time I start to play file there is I2S SYNC error:
bcm2708-dmaengine bcm2708-dmaengine: allocating channel for 0 bcm2708-i2s bcm2708-i2s.0: I2S SYNC error! bcm2708-dmaengine bcm2708-dmaengine: freeing channel for 0