Extend I2S capabilities
authorPawel Sagan <psagan@internships.antmicro.com>
Thu, 12 Mar 2020 13:54:41 +0000 (14:54 +0100)
committerMateusz Holenko <mholenko@antmicro.com>
Wed, 20 May 2020 12:31:51 +0000 (14:31 +0200)
This commit:
* adds the support for I2S standard mode,
* extends I2S left justified mode,
* allows to configure sample size for tx/rx in 1-32 bits range,
* implements I2S master mode,
* allows to concatenate channels or used the padded mode.

This required to rework the FSM.

litex/soc/cores/i2s.py
test/test_i2s.py

index f0554d5f2ebf2d62b6da2b6f18c8c8dd31c9fe8e..2bffa75716bea83b687ab6c84fbcc2fcabf39f73 100644 (file)
@@ -1,36 +1,56 @@
 # This file is Copyright (c) 2020 bunnie <bunnie@kosagi.com>
+# This file is Copyright (c) 2020 Antmicro <www.antmicro.com>
 # License: BSD
 
 from migen.genlib.cdc import MultiReg
 
+from litex.soc.cores.clock import *
 from litex.soc.interconnect import wishbone
 from litex.soc.interconnect.csr_eventmanager import *
 
 from litex.soc.integration.doc import AutoDoc, ModuleDoc
-
-
-class S7I2SSlave(Module, AutoCSR, AutoDoc):
-    def __init__(self, pads, fifo_depth=256):
+from enum import Enum
+import math
+class I2S_FORMAT(Enum):
+    I2S_STANDARD = 1
+    I2S_LEFT_JUSTIFIED = 2
+
+class S7I2S(Module, AutoCSR, AutoDoc):
+    def __init__(self, pads, fifo_depth=256, master=False, concatenate_channels=True, sample_width=16, frame_format=I2S_FORMAT.I2S_LEFT_JUSTIFIED, lrck_ref_freq=100e6, lrck_freq=44100, bits_per_channel=28):
         self.intro = ModuleDoc("""Intro
 
-        I2S slave creates a slave audio interface instance. Tx and Rx interfaces are inferred based
-        upon the presence or absence of the respective pins in the "pads" argument.
+        I2S master/slave creates a master/slave audio interface instance depending on a configured master variable. 
+        Tx and Rx interfaces are inferred based upon the presence or absence of the respective pins in the "pads" argument.
+        
+        When device is configured as master you can manipulate LRCK and SCLK signals using below variables.
+        
+        - lrck_ref_freq - is a reference signal that is required to achive desired LRCK and SCLK frequencies.
+                         Have be the same as your sys_clk.
+        - lrck_freq - this variable defines requested LRCK frequency. Mind you, that based on sys_clk frequency, 
+                         configured value will be more or less acurate.
+        - bits_per_channel - defines SCLK frequency. Mind you, that based on sys_clk frequency, 
+                         the requested amount of bits per channel may vary from configured.
+        
+        When device is configured as slave I2S interface, sampling rate and framing is set by the
+        programming of the audio CODEC chip. A slave configuration defers the
+        generation of audio clocks to the CODEC, which has PLLs specialized to generate the correct
+        frequencies for audio sampling rates.
+
+        I2S core supports two formats: standard and left-justified.
+        
+        - Standard format requires a device to receive and send data with one bit offset for both channels. 
+            Left channel begins with low signal on LRCK.
+        - Left justified format requires from device to receive and send data without any bit offset for both channels.
+            Left channel begins with high signal on LRCK.
+    
+        Sample width can be any of 1 to 32 bits.
 
-        The interface is I2S-like, but note the deviation that the bits are justified left without a
-        1-bit pad after sync edges. This isn't a problem for talking to the LM49352 codec this was
-        designed for, as the bit offset is programmable, but this will not work well if are talking
-        to a CODEC without a programmable bit offset!
+        When sample_width is less than or equal to 16-bit and concatenate_channels is enabled,
+        sending and reciving channels is performed atomically. eg. both samples are transfered from/to fifo in single operation.
 
         System Interface
         ----------------
 
-        Audio interchange is done with the system using 16-bit stereo samples, with the right channel
-        mapped to the least significant word of a 32-bit word. Thus each 32-bit word is a single
-        stereo sample. As this is a slave I2S interface, sampling rate and framing is set by the
-        programming of the audio CODEC chip. A slave situation is preferred because this defers the
-        generation of audio clocks to the CODEC, which has PLLs specialized to generate the correct
-        frequencies for audio sampling rates.
-
         `fifo_depth` is the depth at which either a read interrupt is fired (guaranteeing at least
         `fifo_depth` stereo samples in the receive FIFO) or a write interrupt is fired (guaranteeing
         at least `fifo_depth` free space in the transmit FIFO). The maximum depth is 512.
@@ -84,9 +104,8 @@ class S7I2SSlave(Module, AutoCSR, AutoDoc):
 
         - Data is updated on the falling edge
         - Data is sampled on the rising edge
-        - Words are MSB-to-LSB, left-justified (**NOTE: this is a deviation from strict I2S, which
-          offsets by 1 from the left**)
-        - Sync is an input (FPGA is slave, codec is master): low => left channel, high => right channel
+        - Words are MSB-to-LSB,  
+        - Sync is an input or output based on configure mode,
         - Sync can be longer than the wordlen, extra bits are just ignored
         - Tx is data to the codec (SDI pin on LM49352)
         - Rx is data from the codec (SDO pin on LM49352)
@@ -100,6 +119,9 @@ class S7I2SSlave(Module, AutoCSR, AutoDoc):
         if fifo_depth < 8:
             fifo_depth = 8
             print("I2S warning: fifo depth less than 8 selected; truncating to 8")
+        if sample_width > 32:
+            sample_width = 32
+            print("I2S warning: sample width greater than 32 bits. truncating to 32")
 
         # Connect pins, synchronizers, and edge detectors
         if hasattr(pads, 'tx'):
@@ -108,6 +130,15 @@ class S7I2SSlave(Module, AutoCSR, AutoDoc):
         if hasattr(pads, 'rx'):
             rx_pin = Signal()
             self.specials += MultiReg(pads.rx, rx_pin)
+        
+        fifo_data_width = sample_width
+        if concatenate_channels:
+            if sample_width <= 16:
+                fifo_data_width = sample_width * 2
+            else:
+                concatenate_channels = False
+                print("I2S warning: sample width greater than 16 bits. your channels can't be glued")
+
         sync_pin = Signal()
         self.specials += MultiReg(pads.sync, sync_pin)
 
@@ -123,7 +154,7 @@ class S7I2SSlave(Module, AutoCSR, AutoDoc):
         self.bus = bus = wishbone.Interface()
         rd_ack = Signal()
         wr_ack = Signal()
-        self.comb +=[
+        self.comb += [
             If(bus.we,
                bus.ack.eq(wr_ack),
             ).Else(
@@ -131,6 +162,34 @@ class S7I2SSlave(Module, AutoCSR, AutoDoc):
             )
         ]
 
+
+        if master == True:
+            if bits_per_channel < sample_width and frame_format == I2S_FORMAT.I2S_STANDARD:
+                bits_per_channel = sample_width + 1
+                print("I2S warning: bits per channel can't be smaller than sample_width. Setting bits per channel to {}".format(sample_width + 1))
+            # implementing LRCK signal
+            lrck_period = int(lrck_ref_freq / (lrck_freq * 2))
+            lrck_counter = Signal(16)
+            self.sync += [
+                    If((lrck_counter == lrck_period),
+                        lrck_counter.eq(0),
+                        pads.sync.eq(~pads.sync),
+                    ).Else(
+                        lrck_counter.eq(lrck_counter + 1)
+                    )
+            ]
+            # implementing SCLK signal
+            sclk_period = int(lrck_period / (bits_per_channel * 2))
+            sclk_counter = Signal(16)
+            self.sync += [
+                    If((sclk_counter == sclk_period),
+                        sclk_counter.eq(0),
+                        pads.clk.eq(~pads.clk),
+                    ).Else(
+                        sclk_counter.eq(sclk_counter + 1)
+                    )
+            ]
+
         # Interrupts
         self.submodules.ev = EventManager()
         if hasattr(pads, 'rx'):
@@ -141,10 +200,9 @@ class S7I2SSlave(Module, AutoCSR, AutoDoc):
             self.ev.tx_error = EventSourcePulse(description="Indicates a Tx error has happened (over/underflow")
         self.ev.finalize()
 
-
         # build the RX subsystem
         if hasattr(pads, 'rx'):
-            rx_rd_d        = Signal(32)
+            rx_rd_d        = Signal(fifo_data_width)
             rx_almostfull  = Signal()
             rx_almostempty = Signal()
             rx_full        = Signal()
@@ -154,7 +212,7 @@ class S7I2SSlave(Module, AutoCSR, AutoDoc):
             rx_wrerr       = Signal()
             rx_wrcount     = Signal(9)
             rx_rden        = Signal()
-            rx_wr_d        = Signal(32)
+            rx_wr_d        = Signal(fifo_data_width)
             rx_wren        = Signal()
 
             self.rx_ctl = CSRStorage(description="Rx data path control",
@@ -164,13 +222,20 @@ class S7I2SSlave(Module, AutoCSR, AutoDoc):
                 ])
             self.rx_stat = CSRStatus(description="Rx data path status",
                 fields=[
-                    CSRField("overflow",  size=1, description="Rx overflow"),
+                    CSRField("overflow", size=1, description="Rx overflow"),
                     CSRField("underflow", size=1, description="Rx underflow"),
                     CSRField("dataready", size=1, description="{} words of data loaded and ready to read".format(fifo_depth)),
                     CSRField("empty",     size=1, description="No data available in FIFO to read"), # next flags probably never used
                     CSRField("wrcount",   size=9, description="Write count"),
                     CSRField("rdcount",   size=9, description="Read count"),
-                    CSRField("fifo_depth", size=9, description="FIFO depth as synthesized")
+                    CSRField("fifo_depth", size=9, description="FIFO depth as synthesized"),
+                    CSRField("concatenate_channels", size=1, reset=concatenate_channels, description="Receive and send both channels atomically")
+                ])
+            self.rx_conf = CSRStatus(description="Rx configuration",
+                fields=[
+                    CSRField("format", size=2, reset=frame_format.value, description="I2S sample format. {} is left-justified, {} is I2S standard".format(I2S_FORMAT.I2S_LEFT_JUSTIFIED, I2S_FORMAT.I2S_STANDARD)),
+                    CSRField("sample_width", size=6, reset=sample_width, description="Single sample width"),
+                    CSRField("lrck_freq", size=24, reset=lrck_freq, description="Audio sampling rate frequency"),
                 ])
             self.comb += self.rx_stat.fields.fifo_depth.eq(fifo_depth)
 
@@ -189,11 +254,12 @@ class S7I2SSlave(Module, AutoCSR, AutoDoc):
                     )
                 )
             ]
+
             # At a width of 32 bits, an 18kiB fifo is 512 entries deep
             self.specials += Instance("FIFO_SYNC_MACRO",
                 p_DEVICE              = "7SERIES",
                 p_FIFO_SIZE           = "18Kb",
-                p_DATA_WIDTH          = 32,
+                p_DATA_WIDTH          = fifo_data_width,
                 p_ALMOST_EMPTY_OFFSET = 8,
                 p_ALMOST_FULL_OFFSET  = (512 - fifo_depth),
                 p_DO_REG              = 0,
@@ -213,7 +279,6 @@ class S7I2SSlave(Module, AutoCSR, AutoDoc):
                 o_WRERR       = rx_wrerr,
             )
             self.comb += [  # Wire up the status signals and interrupts
-                self.rx_stat.fields.overflow.eq(rx_wrerr),
                 self.rx_stat.fields.underflow.eq(rx_rderr),
                 self.rx_stat.fields.dataready.eq(rx_almostfull),
                 self.rx_stat.fields.wrcount.eq(rx_wrcount),
@@ -244,23 +309,33 @@ class S7I2SSlave(Module, AutoCSR, AutoDoc):
                 ),
                 rd_ack.eq(rd_ack_pipe),
             ]
+            rx_cnt_width = math.ceil(math.log(fifo_data_width,2))
+            rx_cnt = Signal(rx_cnt_width)
+            rx_delay_cnt = Signal()
+            rx_delay_val = 1 if frame_format == I2S_FORMAT.I2S_STANDARD else 0 
 
-            rx_cnt = Signal(5)
             self.submodules.rxi2s = rxi2s = FSM(reset_state="IDLE")
             rxi2s.act("IDLE",
                 NextValue(rx_wr_d, 0),
                 If(self.rx_ctl.fields.enable,
                     # Wait_sync guarantees we start at the beginning of a left frame, and not in
                     # the middle
-                    If(rising_edge & sync_pin,
-                        NextState("WAIT_SYNC")
+                    If(rising_edge & (~sync_pin if frame_format == I2S_FORMAT.I2S_STANDARD else sync_pin),
+                        NextState("WAIT_SYNC"),
+                        NextValue(rx_delay_cnt, rx_delay_val)
                    )
                 )
             ),
             rxi2s.act("WAIT_SYNC",
-                If(rising_edge & ~sync_pin,
-                    NextState("LEFT"),
-                    NextValue(rx_cnt, 16)
+                If(rising_edge & (~sync_pin if frame_format == I2S_FORMAT.I2S_STANDARD else sync_pin),
+                    If(rx_delay_cnt > 0,
+                        NextValue(rx_delay_cnt, rx_delay_cnt - 1),
+                        NextState("WAIT_SYNC")
+                    ).Else(
+                        NextState("LEFT"),
+                        NextValue(rx_delay_cnt, rx_delay_val),
+                        NextValue(rx_cnt, sample_width)
+                    )
                 ),
             )
             rxi2s.act("LEFT",
@@ -272,20 +347,58 @@ class S7I2SSlave(Module, AutoCSR, AutoDoc):
                     NextState("LEFT_WAIT")
                 )
             )
-            rxi2s.act("LEFT_WAIT",
-                If(~self.rx_ctl.fields.enable,
-                    NextState("IDLE")
-                ).Else(
-                    If(rising_edge,
-                        If((rx_cnt == 0) & sync_pin,
-                            NextValue(rx_cnt, 16),
-                            NextState("RIGHT")
-                        ).Elif(rx_cnt > 0,
-                            NextState("LEFT")
+            if concatenate_channels:
+                rxi2s.act("LEFT_WAIT",
+                    If(~self.rx_ctl.fields.enable,
+                        NextState("IDLE")
+                    ).Else(
+                        If(rising_edge,
+                            If((rx_cnt == 0),
+                                If((sync_pin if frame_format == I2S_FORMAT.I2S_STANDARD else ~sync_pin),
+                                    If(rx_delay_cnt == 0,
+                                        NextValue(rx_cnt, sample_width),
+                                        NextValue(rx_delay_cnt,rx_delay_val),
+                                        NextState("RIGHT"),
+                                    ).Else(
+                                        NextValue(rx_delay_cnt, rx_delay_cnt - 1),
+                                        NextState("LEFT_WAIT")
+                                    )
+                                ).Else(
+                                    NextState("LEFT_WAIT")
+                                )
+                            ).Elif(rx_cnt > 0,
+                                NextState("LEFT")
+                            )
                         )
                     )
                 )
-            )
+            else:
+                rxi2s.act("LEFT_WAIT",
+                    If(~self.rx_ctl.fields.enable,
+                        NextState("IDLE")
+                    ).Else(
+                        If(rising_edge,
+                            If((rx_cnt == 0),
+                                If((sync_pin if frame_format == I2S_FORMAT.I2S_STANDARD else ~sync_pin),
+                                    If(rx_delay_cnt == 0,
+                                        NextValue(rx_cnt, sample_width),
+                                        NextValue(rx_delay_cnt,rx_delay_val),
+                                        NextState("RIGHT"),
+                                        rx_wren.eq(1) # Pulse rx_wren to write the current data word
+                                    ).Else(
+                                        NextValue(rx_delay_cnt, rx_delay_cnt - 1),
+                                        NextState("LEFT_WAIT")
+                                    )
+                                ).Else(
+                                    NextState("LEFT_WAIT")
+                                )
+                            ).Elif(rx_cnt > 0,
+                                NextState("LEFT")
+                            )
+                        )
+                    )
+                )
+
             rxi2s.act("RIGHT",
                 If(~self.rx_ctl.fields.enable,
                     NextState("IDLE")
@@ -300,10 +413,16 @@ class S7I2SSlave(Module, AutoCSR, AutoDoc):
                     NextState("IDLE")
                 ).Else(
                     If(rising_edge,
-                        If((rx_cnt == 0) & ~sync_pin,
-                            NextValue(rx_cnt, 16),
-                            NextState("LEFT"),
-                            rx_wren.eq(1) # Pulse rx_wren to write the current data word
+                        If((rx_cnt == 0) & (~sync_pin if frame_format == I2S_FORMAT.I2S_STANDARD else sync_pin),
+                            If(rx_delay_cnt == 0,
+                                NextValue(rx_cnt, sample_width),
+                                NextValue(rx_delay_cnt,rx_delay_val),
+                                NextState("LEFT"),
+                                rx_wren.eq(1) # Pulse rx_wren to write the current data word
+                            ).Else(
+                                NextValue(rx_delay_cnt, rx_delay_cnt - 1),
+                                NextState("RIGHT_WAIT")
+                            )
                         ).Elif(rx_cnt > 0,
                             NextState("RIGHT")
                         )
@@ -314,7 +433,7 @@ class S7I2SSlave(Module, AutoCSR, AutoDoc):
 
         # Build the TX subsystem
         if hasattr(pads, 'tx'):
-            tx_rd_d        = Signal(32)
+            tx_rd_d        = Signal(fifo_data_width)
             tx_almostfull  = Signal()
             tx_almostempty = Signal()
             tx_full        = Signal()
@@ -324,7 +443,7 @@ class S7I2SSlave(Module, AutoCSR, AutoDoc):
             tx_wrerr       = Signal()
             tx_wrcount     = Signal(9)
             tx_rden        = Signal()
-            tx_wr_d        = Signal(32)
+            tx_wr_d        = Signal(fifo_data_width)
             tx_wren        = Signal()
 
             self.tx_ctl = CSRStorage(description="Tx data path control",
@@ -334,7 +453,7 @@ class S7I2SSlave(Module, AutoCSR, AutoDoc):
                 ])
             self.tx_stat = CSRStatus(description="Tx data path status",
                 fields=[
-                    CSRField("overflow",   size=1, description="Tx overflow"),
+                    CSRField("overflow",  size=1, description="Tx overflow"),
                     CSRField("underflow",  size=1, description="Tx underflow"),
                     CSRField("free",       size=1, description="At least {} words of space free".format(fifo_depth)),
                     CSRField("almostfull", size=1, description="Less than 8 words space available"), # the next few flags should be rarely used
@@ -342,6 +461,13 @@ class S7I2SSlave(Module, AutoCSR, AutoDoc):
                     CSRField("empty",      size=1, description="FIFO is empty"),
                     CSRField("wrcount",    size=9, description="Tx write count"),
                     CSRField("rdcount",    size=9, description="Tx read count"),
+                    CSRField("concatenate_channels", size=1, reset=concatenate_channels, description="Receive and send both channels atomically")
+                ])
+            self.tx_conf = CSRStatus(description="TX configuration",
+                fields=[
+                    CSRField("format", size=2, reset=frame_format.value, description="I2S sample format. {} is left-justified, {} is I2S standard".format(I2S_FORMAT.I2S_LEFT_JUSTIFIED, I2S_FORMAT.I2S_STANDARD)),
+                    CSRField("sample_width", size=6, reset=sample_width, description="Single sample width"),
+                    CSRField("lrck_freq", size=24, reset=lrck_freq, description="Audio sampling rate frequency"),
                 ])
 
             tx_rst_cnt = Signal(3)
@@ -359,11 +485,12 @@ class S7I2SSlave(Module, AutoCSR, AutoDoc):
                     )
                 )
             ]
+
             # At a width of 32 bits, an 18kiB fifo is 512 entries deep
             self.specials += Instance("FIFO_SYNC_MACRO",
                 p_DEVICE              = "7SERIES",
                 p_FIFO_SIZE           = "18Kb",
-                p_DATA_WIDTH          = 32,
+                p_DATA_WIDTH          = fifo_data_width,
                 p_ALMOST_EMPTY_OFFSET = fifo_depth,
                 p_ALMOST_FULL_OFFSET  = 8,
                 p_DO_REG              = 0,
@@ -384,7 +511,6 @@ class S7I2SSlave(Module, AutoCSR, AutoDoc):
             )
 
             self.comb += [  # Wire up the status signals and interrupts
-                self.tx_stat.fields.overflow.eq(tx_wrerr),
                 self.tx_stat.fields.underflow.eq(tx_rderr),
                 self.tx_stat.fields.free.eq(tx_almostempty),
                 self.tx_stat.fields.almostfull.eq(tx_almostfull),
@@ -397,7 +523,7 @@ class S7I2SSlave(Module, AutoCSR, AutoDoc):
             ]
             self.sync += [
                 # This is the bus responder -- need to check how this interacts with uncached memory
-                # region
+                # region 
                 If(bus.cyc & bus.stb & bus.we & ~bus.ack,
                    If(~tx_full,
                       tx_wr_d.eq(bus.dat_w),
@@ -413,53 +539,86 @@ class S7I2SSlave(Module, AutoCSR, AutoDoc):
                 )
             ]
 
-            tx_cnt = Signal(5)
-            tx_buf = Signal(32)
+            tx_buf_width = fifo_data_width + 1 if frame_format == I2S_FORMAT.I2S_STANDARD else fifo_data_width
+            sample_width = sample_width + 1 if frame_format == I2S_FORMAT.I2S_STANDARD else sample_width
+            offset = [0] if frame_format == I2S_FORMAT.I2S_STANDARD else []
+
+            tx_cnt_width = math.ceil(math.log(fifo_data_width,2))
+            tx_cnt = Signal(tx_cnt_width)
+            tx_buf = Signal(tx_buf_width)
+            sample_msb = fifo_data_width - 1
             self.submodules.txi2s = txi2s = FSM(reset_state="IDLE")
             txi2s.act("IDLE",
                 If(self.tx_ctl.fields.enable,
-                    If(falling_edge & sync_pin,
+                    If(falling_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(falling_edge & (~sync_pin if frame_format == I2S_FORMAT.I2S_STANDARD else sync_pin),
                     NextState("LEFT"),
-                    NextValue(tx_cnt, 16),
-                    NextValue(tx_buf, tx_rd_d),
-                    tx_rden.eq(1)
+                    NextValue(tx_cnt, sample_width),
+                    NextValue(tx_buf, Cat(tx_rd_d, offset)),
+                    tx_rden.eq(1),
                 )
             )
             txi2s.act("LEFT",
                 If(~self.tx_ctl.fields.enable,
                     NextState("IDLE")
                 ).Else(
-                    NextValue(tx_pin, tx_buf[31]),
+                    NextValue(tx_pin, tx_buf[sample_msb]),
                     NextValue(tx_buf, Cat(0, tx_buf[:-1])),
                     NextValue(tx_cnt, tx_cnt - 1),
                     NextState("LEFT_WAIT")
                 )
             )
-            txi2s.act("LEFT_WAIT",
-                If(~self.tx_ctl.fields.enable,
-                    NextState("IDLE")
-                ).Else(
-                    If(falling_edge,
-                        If((tx_cnt == 0) & sync_pin,
-                            NextValue(tx_cnt, 16),
-                            NextState("RIGHT")
-                        ).Elif(tx_cnt > 0,
-                            NextState("LEFT")
+            if concatenate_channels:
+                txi2s.act("LEFT_WAIT",
+                    If(~self.tx_ctl.fields.enable,
+                        NextState("IDLE")
+                    ).Else(
+                        If(falling_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"),
+                                ).Else(
+                                    NextState("LEFT_WAIT"),
+                                )
+                            ).Elif(tx_cnt > 0,
+                                NextState("LEFT"),
+                            )
                         )
                     )
                 )
-            )
+            else:
+                txi2s.act("LEFT_WAIT",
+                    If(~self.tx_ctl.fields.enable,
+                        NextState("IDLE")
+                    ).Else(
+                        If(falling_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"),
+                                    NextValue(tx_buf, Cat(tx_rd_d,offset)),
+                                    tx_rden.eq(1),
+                                ).Else(
+                                    NextState("LEFT_WAIT"),
+                                )
+                            ).Elif(tx_cnt > 0,
+                                NextState("LEFT"),
+                            )
+                        )
+                    )
+                )
+
             txi2s.act("RIGHT",
                 If(~self.tx_ctl.fields.enable,
                     NextState("IDLE")
                 ).Else(
-                    NextValue(tx_pin, tx_buf[31]),
+                    NextValue(tx_pin, tx_buf[sample_msb]),
                     NextValue(tx_buf, Cat(0, tx_buf[:-1])),
                     NextValue(tx_cnt, tx_cnt - 1),
                     NextState("RIGHT_WAIT")
@@ -470,10 +629,10 @@ class S7I2SSlave(Module, AutoCSR, AutoDoc):
                     NextState("IDLE")
                 ).Else(
                     If(falling_edge,
-                        If((tx_cnt == 0) & ~sync_pin,
-                            NextValue(tx_cnt, 16),
+                        If((tx_cnt == 0) & (~sync_pin if frame_format == I2S_FORMAT.I2S_STANDARD else sync_pin),
+                            NextValue(tx_cnt, sample_width),
                             NextState("LEFT"),
-                            NextValue(tx_buf, tx_rd_d),
+                            NextValue(tx_buf, Cat(tx_rd_d,offset)),
                             tx_rden.eq(1)
                         ).Elif(tx_cnt > 0,
                             NextState("RIGHT")
index 06b660210b51749c4622d2934804b6194d073421..80700461c2dd111a41f78333f1fbfe506b626bea 100644 (file)
@@ -5,11 +5,11 @@ import unittest
 
 from migen import *
 
-from litex.soc.cores.i2s import S7I2SSlave
+from litex.soc.cores.i2s import S7I2S
 
 
 class TestI2S(unittest.TestCase):
     def test_s7i2sslave_syntax(self):
         i2s_pads = Record([("rx", 1), ("tx", 1), ("sync", 1), ("clk", 1)])
-        i2s = S7I2SSlave(pads=i2s_pads, fifo_depth=256)
+        i2s = S7I2S(pads=i2s_pads, fifo_depth=256)