{"id":722,"date":"2015-05-19T13:59:02","date_gmt":"2015-05-19T21:59:02","guid":{"rendered":"http:\/\/www.beyond-circuits.com\/wordpress\/?page_id=722"},"modified":"2026-10-23T13:46:43","modified_gmt":"2026-10-23T21:46:43","slug":"tutorial19","status":"publish","type":"page","link":"https:\/\/www.beyond-circuits.com\/wordpress\/tutorial\/tutorial19\/","title":{"rendered":"Tutorial 19: I2S Transmitter"},"content":{"rendered":"<h1>I2S Transmitter Spec<\/h1>\n<p>Let&#8217;s take a look at the block diagram for an example transmitter from the I2S spec. It is shown below:<\/p>\n<div id=\"attachment_789\" style=\"width: 824px\" class=\"wp-caption alignright\"><a href=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/04\/tutorial19_bd.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-789\" class=\"wp-image-789 size-full\" src=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/04\/tutorial19_bd.png\" alt=\"I2S transmitter block diagram\" width=\"814\" height=\"591\" srcset=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/04\/tutorial19_bd.png 814w, https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/04\/tutorial19_bd-300x218.png 300w, https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/04\/tutorial19_bd-413x300.png 413w\" sizes=\"auto, (max-width: 814px) 100vw, 814px\" \/><\/a><p id=\"caption-attachment-789\" class=\"wp-caption-text\">I2S transmitter block diagram<\/p><\/div>\n<p>I have also created a timing diagram for the circuit shown in the block diagram. It is shown below:<\/p>\n<div id=\"attachment_793\" style=\"width: 1020px\" class=\"wp-caption alignnone\"><a href=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/04\/tutorial19_timing_1.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-793\" class=\"wp-image-793 size-full\" src=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/04\/tutorial19_timing_1.png\" alt=\"tutorial19_timing_1\" width=\"1010\" height=\"352\" srcset=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/04\/tutorial19_timing_1.png 1010w, https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/04\/tutorial19_timing_1-300x105.png 300w, https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/04\/tutorial19_timing_1-500x174.png 500w, https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/04\/tutorial19_timing_1-900x314.png 900w\" sizes=\"auto, (max-width: 1010px) 100vw, 1010px\" \/><\/a><p id=\"caption-attachment-793\" class=\"wp-caption-text\">I2S transmitter timing diagram<\/p><\/div>\n<p>The really important thing to note about the design is the parallel load. The authors of the specification don&#8217;t really explain what this means, but based on the requirement that <em>sd<\/em> change on the falling edge of <em>sck<\/em>, we can infer they mean what is shown in the detailed block diagram below. In this diagram, I have shown the details of the most significant bit of the shift register. Notice that we have the <em>wsp<\/em> signal being generated on the rising edge of <em>sck<\/em>, but it is captured on the falling edge of <em>sck<\/em>. This makes the circuit dependent on the duty cycle of the sck clock. If it is high for a short period of time we could run into timing issues with the design.<\/p>\n<div id=\"attachment_792\" style=\"width: 955px\" class=\"wp-caption alignnone\"><a href=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/04\/tutorial19_detail_bd.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-792\" class=\"wp-image-792 size-full\" src=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/04\/tutorial19_detail_bd.png\" alt=\"I2S transmitter block diagram details\" width=\"945\" height=\"447\" srcset=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/04\/tutorial19_detail_bd.png 945w, https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/04\/tutorial19_detail_bd-300x142.png 300w, https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/04\/tutorial19_detail_bd-500x237.png 500w, https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/04\/tutorial19_detail_bd-900x426.png 900w\" sizes=\"auto, (max-width: 945px) 100vw, 945px\" \/><\/a><p id=\"caption-attachment-792\" class=\"wp-caption-text\">I2S transmitter block diagram details<\/p><\/div>\n<h1>Changing to the FPGA clock domain<\/h1>\n<p>We want to modify the design such that it uses the FPGA clock domain rather than <em>sck<\/em>. If we just use <em>S_AXIS_ACLK<\/em> and condition the flip-flops on <em>sck_rise<\/em> and <em>sck_fall<\/em> where appropriate, we would get a timing diagram like that shown below:<\/p>\n<div id=\"attachment_794\" style=\"width: 1005px\" class=\"wp-caption alignnone\"><a href=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/04\/tutorial19_timing_2.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-794\" class=\"size-full wp-image-794\" src=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/04\/tutorial19_timing_2.png\" alt=\"Timing diagram of delay caused by sampling sck\" width=\"995\" height=\"297\" srcset=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/04\/tutorial19_timing_2.png 995w, https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/04\/tutorial19_timing_2-300x90.png 300w, https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/04\/tutorial19_timing_2-500x149.png 500w, https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/04\/tutorial19_timing_2-900x269.png 900w\" sizes=\"auto, (max-width: 995px) 100vw, 995px\" \/><\/a><p id=\"caption-attachment-794\" class=\"wp-caption-text\">Timing diagram of delay caused by sampling <em>sck<\/em><\/p><\/div>\n<p>Notice how long it takes from the fall os <em>sck<\/em> to the change in the output data <em>sd<\/em>. This can take up to two <em>S_AXIS_ACLK<\/em> clock cycles. The I2S specification says this is supposed to change when <em>sck<\/em> falls. We can fix this by shifting the data on the rise of <em>sck<\/em> but then using a flip-flop clocked off the actual falling edge of <em>sck<\/em> to generate the data out of the chip. In this situation, it&#8217;s not really a big deal to use <em>sck<\/em> as an actual clock, since it is only going to a single flip-flop. We don&#8217;t need to use dedicated clock resources on the FPGA to do this since there is no requirement that skew on the clock tree be balanced. It is balanced by construction because there is only a single clock tree leaf.<\/p>\n<p>The timing diagram below shows the result of doing this. Notice how the <em>sd<\/em> output is pulled back closer to the falling edge of <em>sck:<\/em><\/p>\n<div id=\"attachment_795\" style=\"width: 1007px\" class=\"wp-caption alignnone\"><a href=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/04\/tutorial19_timing_3.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-795\" class=\"size-full wp-image-795\" src=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/04\/tutorial19_timing_3.png\" alt=\"Timing diagram detailing reduced delay by clocking sd and ws on the falling edge of sck\" width=\"997\" height=\"358\" srcset=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/04\/tutorial19_timing_3.png 997w, https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/04\/tutorial19_timing_3-300x108.png 300w, https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/04\/tutorial19_timing_3-500x180.png 500w, https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/04\/tutorial19_timing_3-900x323.png 900w\" sizes=\"auto, (max-width: 997px) 100vw, 997px\" \/><\/a><p id=\"caption-attachment-795\" class=\"wp-caption-text\">Timing diagram detailing reduced delay by clocking <em>sd<\/em>\u00a0on the falling edge of <em>sck<\/em><\/p><\/div>\n<p>A schematic of this is shown below.<\/p>\n<div id=\"attachment_791\" style=\"width: 1137px\" class=\"wp-caption alignnone\"><a href=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/04\/tutorial19_bd_2.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-791\" class=\"size-full wp-image-791\" src=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/04\/tutorial19_bd_2.png\" alt=\"Clocking sd out on the falling edge of sck\" width=\"1127\" height=\"497\" \/><\/a><p id=\"caption-attachment-791\" class=\"wp-caption-text\">Clocking <em>sd<\/em> out on the falling edge of <em>sck<\/em><\/p><\/div>\n<p>There are some problems with the design the way it is shown, though. First, we observed previously that the <em>wsp<\/em> signal was generated on the rising edge of <em>sck,<\/em> but used on the falling when we load the shift register using the parallel load feature. If we use the logic as it is shown then the <em>wsp<\/em> pulse will last too long and on the next cycle when we should do a shift we will again do a parallel load. The fix is to not condition the second flip-flop on the <em>sck_rise<\/em> signal. This will keep <em>wsp<\/em> as a single clock pulse in the <em>S_AXIS_ACLK<\/em> domain. This of course means that wsp will not be true while sck_rise is true so we need to remove the enable when the shift register does the parallel load. But of course, we need to keep the enable condition when it comes to shifting the data in the shift register. Our modified design looks something like this:<\/p>\n<div id=\"attachment_791-2\" style=\"width: 1137px\" class=\"wp-caption alignnone\"><a href=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/04\/tutorial19_bd_3.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-791-2\" class=\"size-full wp-image-791\" src=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/04\/tutorial19_bd_3.png\" alt=\"Final I2S transmit block diagram\" width=\"1127\" height=\"497\" srcset=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/04\/tutorial19_bd_3.png 1127w, https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/04\/tutorial19_bd_3-300x132.png 300w, https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/04\/tutorial19_bd_3-1024x452.png 1024w, https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/04\/tutorial19_bd_3-500x220.png 500w, https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/04\/tutorial19_bd_3-900x397.png 900w\" sizes=\"auto, (max-width: 1127px) 100vw, 1127px\" \/><\/a><p id=\"caption-attachment-791-2\" class=\"wp-caption-text\">Final I2S transmit block diagram<\/p><\/div>\n<h1>Test<\/h1>\n<p>The test will instantiate your <em>i2s_transmit<\/em> module and an AXI 4 streaming master module to connect to the slave interface on your design. The basic premise of the test is that it tells the AXI master to write audio data to your transmitter. Your transmitter should take the audio data and write it out the I2S audio interface. The test will drive the audio clock <em>sck<\/em> and the left\/right channel signal <em>ws<\/em>. Your i2s_transmit module will drive the <em>sd<\/em> serial data signal. The serial data will be compared against the audio data sent by the AXI streaming master. The figure below illustrates this.<\/p>\n<div id=\"attachment_845\" style=\"width: 889px\" class=\"wp-caption alignnone\"><a href=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/05\/tutorial19_overview_bd.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-845\" class=\"wp-image-845 size-full\" src=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/05\/tutorial19_overview_bd.png\" alt=\"I2S transmitter test block diagram\" width=\"879\" height=\"654\" srcset=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/05\/tutorial19_overview_bd.png 879w, https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/05\/tutorial19_overview_bd-300x223.png 300w, https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/2015\/05\/tutorial19_overview_bd-403x300.png 403w\" sizes=\"auto, (max-width: 879px) 100vw, 879px\" \/><\/a><p id=\"caption-attachment-845\" class=\"wp-caption-text\">I2S transmitter test block diagram<\/p><\/div>\n<p>The <em>ws<\/em> signal will not be a consistent number of clocks for each sample. The test will vary this period, and your design should accommodate this. Also, your design must keep up with the data driven by the AXI streaming master. While your design determines when it can accept data by asserting the <em>S_AXIS_TREADY<\/em> signal, it must not wait too long to do so. If your design does not keep up, the test will terminate with an error.<\/p>\n<h1>Wrap-up<\/h1>\n<p>You still need to design the logic to take data from <em>S_AXIS_TDATA<\/em> and put it in your data_left and data_right registers. You will also need to design some logic to generate <em>S_AXIS_TREADY<\/em> to tell the AXI4 Streaming master that you are ready to accept data. I won&#8217;t go into detail on that for now so you can have a chance to work it out on your own.<\/p>\n<p>Here are some links to my testbench files:<\/p>\n<ul>\n<li><a href=\"https:\/\/www.beyond-circuits.com\/repos\/tutorial\/trunk\/tests\/i2s_transmit_test.v\">i2s_transmit_test.v<\/a><\/li>\n<li><a href=\"https:\/\/www.beyond-circuits.com\/repos\/tutorial\/trunk\/tbench\/queue.v\">queue.v<\/a><\/li>\n<li><a href=\"https:\/\/www.beyond-circuits.com\/repos\/tutorial\/trunk\/tbench\/common_test_util.v\">common_test_util.v<\/a><\/li>\n<li><a href=\"https:\/\/www.beyond-circuits.com\/wordpress\/wp-content\/uploads\/tutorials\/tutorial19\/axi4_streaming_master_bfm.v\">axi4_streaming_master_bfm.v<\/a><\/li>\n<\/ul>\n<p><strong>Update (October 2026):<\/strong> Some readers using newer versions of Vivado saw the testbench comparisons come out one sample off. The cause was a race in the testbench: <code>output_checking_enabled<\/code> was set with a blocking assignment on the same clock edge the checkers read it, so the result depended on the simulator&#8217;s scheduling order. It now uses a nonblocking assignment (<code>output_checking_enabled &lt;= 1;<\/code>). If you downloaded <em>i2s_transmit_test.v<\/em> before this, grab the updated copy above. Thanks to Zdzislaw and detiber for reporting it.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I2S Transmitter Spec Let&#8217;s take a look at the block diagram for an example transmitter from the I2S spec. It is shown below: I have also created a timing diagram for the circuit shown in the block diagram. It is &hellip; <a href=\"https:\/\/www.beyond-circuits.com\/wordpress\/tutorial\/tutorial19\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"parent":226,"menu_order":19,"comment_status":"open","ping_status":"open","template":"","meta":{"footnotes":""},"class_list":["post-722","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/www.beyond-circuits.com\/wordpress\/wp-json\/wp\/v2\/pages\/722","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.beyond-circuits.com\/wordpress\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.beyond-circuits.com\/wordpress\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.beyond-circuits.com\/wordpress\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.beyond-circuits.com\/wordpress\/wp-json\/wp\/v2\/comments?post=722"}],"version-history":[{"count":20,"href":"https:\/\/www.beyond-circuits.com\/wordpress\/wp-json\/wp\/v2\/pages\/722\/revisions"}],"predecessor-version":[{"id":1384,"href":"https:\/\/www.beyond-circuits.com\/wordpress\/wp-json\/wp\/v2\/pages\/722\/revisions\/1384"}],"up":[{"embeddable":true,"href":"https:\/\/www.beyond-circuits.com\/wordpress\/wp-json\/wp\/v2\/pages\/226"}],"wp:attachment":[{"href":"https:\/\/www.beyond-circuits.com\/wordpress\/wp-json\/wp\/v2\/media?parent=722"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}