I2S fix: sample SYNC on the correct edge (#904)

* resolve issue #862 add description to soc.svd

The issue is that with no description provided it simply would
not put out a description tag, which breaks compatibility with
other programs.

Insert a somewhat useful default description including a timestamp
and the words "LiteX SoC".

* I2S fix: sample SYNC on the correct edge

The original Tx path implementation samples SYNC on the falling
edge, out of convenience with the fact that teh data must also
change on the falling edge.

This works OK, until you have a CODEC which has a ~40ns max
delay spec on the SYNC, and also has a slightly asymmetric
SYNC edge (the SYNC signal is also the WCLK or LRCLK depending on
which docs you read). The SYNC by spec is supposed to change
on the falling edge, and this extra delay is enough to cause
the SYNC to introduce occassional bit or frame shifts into
the audio.

This fix samples the SYNC on the rising edge, but still
changes the data on the falling edge, thus allowing for
implementations where SYNC has quite loose timings relative
to everything else (as is the case on the TLV320AIC3200)
This commit is contained in:
bunnie 2021-05-07 14:17:49 +08:00 committed by GitHub
parent 01a7ff44d2
commit 53982acd9f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 23 additions and 12 deletions

View File

@ -559,19 +559,25 @@ class S7I2S(Module, AutoCSR, AutoDoc):
self.submodules.txi2s = txi2s = FSM(reset_state="IDLE")
txi2s.act("IDLE",
If(self.tx_ctl.fields.enable,
If(falling_edge & (~sync_pin if frame_format == I2S_FORMAT.I2S_STANDARD else sync_pin),
If(rising_edge & (~sync_pin if frame_format == I2S_FORMAT.I2S_STANDARD else sync_pin),
NextState("WAIT_SYNC"),
)
)
),
txi2s.act("WAIT_SYNC",
If(falling_edge & (~sync_pin if frame_format == I2S_FORMAT.I2S_STANDARD else sync_pin),
NextState("LEFT"),
If(rising_edge & (~sync_pin if frame_format == I2S_FORMAT.I2S_STANDARD else sync_pin),
NextState("LEFT_FALL"),
NextValue(tx_cnt, sample_width),
NextValue(tx_buf, Cat(tx_rd_d, offset)),
tx_rden.eq(1),
)
)
# sync should be sampled on rising edge, but data should change on falling edge
txi2s.act("LEFT_FALL",
If(falling_edge,
NextState("LEFT")
)
)
txi2s.act("LEFT",
If(~self.tx_ctl.fields.enable,
NextState("IDLE")
@ -587,7 +593,7 @@ class S7I2S(Module, AutoCSR, AutoDoc):
If(~self.tx_ctl.fields.enable,
NextState("IDLE")
).Else(
If(falling_edge,
If(rising_edge,
If((tx_cnt == 0),
If((sync_pin if frame_format == I2S_FORMAT.I2S_STANDARD else ~sync_pin),
NextValue(tx_cnt, sample_width),
@ -596,7 +602,7 @@ class S7I2S(Module, AutoCSR, AutoDoc):
NextState("LEFT_WAIT"),
)
).Elif(tx_cnt > 0,
NextState("LEFT"),
NextState("LEFT_FALL"),
)
)
)
@ -606,23 +612,28 @@ class S7I2S(Module, AutoCSR, AutoDoc):
If(~self.tx_ctl.fields.enable,
NextState("IDLE")
).Else(
If(falling_edge,
If(rising_edge,
If((tx_cnt == 0),
If((sync_pin if frame_format == I2S_FORMAT.I2S_STANDARD else ~sync_pin),
NextValue(tx_cnt, sample_width),
NextState("RIGHT"),
NextState("RIGHT_FALL"),
NextValue(tx_buf, Cat(tx_rd_d,offset)),
tx_rden.eq(1),
).Else(
NextState("LEFT_WAIT"),
)
).Elif(tx_cnt > 0,
NextState("LEFT"),
NextState("LEFT_FALL"),
)
)
)
)
# sync should be sampled on rising edge, but data should change on falling edge
txi2s.act("RIGHT_FALL",
If(falling_edge,
NextState("RIGHT")
)
)
txi2s.act("RIGHT",
If(~self.tx_ctl.fields.enable,
NextState("IDLE")
@ -637,14 +648,14 @@ class S7I2S(Module, AutoCSR, AutoDoc):
If(~self.tx_ctl.fields.enable,
NextState("IDLE")
).Else(
If(falling_edge,
If(rising_edge,
If((tx_cnt == 0) & (~sync_pin if frame_format == I2S_FORMAT.I2S_STANDARD else sync_pin),
NextValue(tx_cnt, sample_width),
NextState("LEFT"),
NextState("LEFT_FALL"),
NextValue(tx_buf, Cat(tx_rd_d,offset)),
tx_rden.eq(1)
).Elif(tx_cnt > 0,
NextState("RIGHT")
NextState("RIGHT_FALL")
)
)
)