{"id":1718,"date":"2021-09-23T21:14:51","date_gmt":"2021-09-23T21:14:51","guid":{"rendered":"http:\/\/retroramblings.net\/?p=1718"},"modified":"2021-09-24T18:08:09","modified_gmt":"2021-09-24T18:08:09","slug":"snake-charming-with-usb-audio","status":"publish","type":"post","link":"https:\/\/retroramblings.net\/?p=1718","title":{"rendered":"Snake Charming with USB Audio&#8230;"},"content":{"rendered":"\n<p><strong>2021-09-23<\/strong><\/p>\n\n\n\n<p>A few months ago I bought a couple of the ridiculously cheap DECA boards from Arrow &#8211; they&#8217;re sadly sold out now &#8211; but $37 bought you a MAX10 FPGA with 50,000 LEs, some DDR3 RAM, i2s audio, an HDMI port, USB and network ports, and a couple of GPIO headers.  (It also bought you <em>all<\/em> the blue LEDs &#8211; I highly recommend not looking directly at the board when you power it up for the first time!)<\/p>\n\n\n\n<p>I&#8217;m not the only one who&#8217;s been interested by this board &#8211; a bunch of MiST and MiSTer cores have already been ported to a DECA-based reference platform which involves a MiSTer-style SDRAM module, PS\/2 keyboard, DB9 joystick and VGA video on the GPIO headers. <\/p>\n\n\n\n<p>There is now an <a href=\"https:\/\/github.com\/BrianHGinc\/BrianHG-DDR3-Controller.git\">open-source DDR3 memory controller<\/a> which has DECA as a main supported target.<\/p>\n\n\n\n<p>And there is a project which caught my attention recently, which turns the <a href=\"https:\/\/github.com\/hansfbaier\/deca-usb2-audio-interface\">DECA board into an external USB2 soundcard<\/a>.<\/p>\n\n\n\n<p>Yes, you read that correctly.<\/p>\n\n\n\n<p>Naturally I wanted to try this out, so I cloned the repo on my own machine.  Hmmm&#8230; there seems to be lots of Python involved.  I&#8217;m not familiar with Python, but by now it&#8217;s a well-established, mature language with reliable, well-thought-out packaging and dependency management, right?<\/p>\n\n\n\n<!--more-->\n\n\n\n<p>Finished laughing yet?  Good &#8211; here&#8217;s exactly how smoothly it went: <\/p>\n\n\n\n<p>(All snarkiness aside, this is a great project and I highly recommend checking it out &#8211; the roadblocks I encountered were mostly related to python &#8211; and probably my lack of familiarity with it &#8211; rather than the project itself.  My intention here is partly to document and share the workarounds I needed to use, and &#8211; I&#8217;ll admit &#8211; partly to vent frustrations with the papercuts sustained along the way!)<\/p>\n\n\n\n<p>[Edit: The author, Hans Baier, has made binaries available, so you can skip this entire setup-and-build process if you wish &#8211; see <a href=\"https:\/\/github.com\/hansfbaier\/deca-usb2-audio-interface\/releases\">https:\/\/github.com\/hansfbaier\/deca-usb2-audio-interface\/releases<\/a>.  Alternatively, if you want to laugh at me fumbling my way through getting the python environment set up &#8211; or you&#8217;ve just encountered the same hurdles I did and are looking for workarounds &#8211; read on!]<\/p>\n\n\n\n<p>Since my last post, I&#8217;m &#8220;auditioning&#8221; Linux distros, and this week&#8217;s candidate is stock Ubuntu LTS &#8211; mainstream enough that I shouldn&#8217;t be too far off the road-well-trodden.<\/p>\n\n\n\n<p>So inside in the repo is a gateware directory which contains the various parts of the project written in nmigen (which is Python based), and an &#8220;initialize-python-environment.sh&#8221; script.  Well it&#8217;s a bad plan to run a random script from the internet without looking at it first, so&#8230;<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">!\/bin\/bash<br>python3 -m venv venv<br>. venv\/bin\/activate<br>pip3 install -r requirements.tx<\/pre>\n\n\n\n<p>OK that&#8217;s simple enough &#8211; let&#8217;s run it:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">ERROR: Command errored out with exit status 1:<br>    command: \/home\/amr\/deca-usb2-audio-interface\/gateware\/venv\/bin\/python3 -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '\"'\"'\/tmp\/pip-install-o1r7mv_x\/usb-protocol\/setup.py'\"'\"'; <strong>file<\/strong>='\"'\"'\/tmp\/pip-install-o1r7mv_x\/usb-protocol\/setup.py'\"'\"';f=getattr(tokenize, '\"'\"'open'\"'\"', open)(<strong>file<\/strong>);code=f.read().replace('\"'\"'\\r\\n'\"'\"', <code>  2'h0:       (* src = \"\/home\/amr\/deca-usb2-audio-interface\/gateware\/venv\/lib\/python3.8\/site-packages\/nmigen_library\/utils\/timer.py:42\" *)       casez (1'h0)       endcase<\/code>'\"'\"'\\n'\"'\"');f.close();exec(compile(code, <strong>file<\/strong>, '\"'\"'exec'\"'\"'))' bdist_wheel -d \/tmp\/pip-wheel-_ekod9ko<br>        cwd: \/tmp\/pip-install-o1r7mv_x\/usb-protocol\/<br>   Complete output (32 lines):<br>   WARNING: The wheel package is not available.<br>   WARNING: The wheel package is not available.<br>   WARNING: The wheel package is not available.<br>   WARNING: The wheel package is not available.<br>   \/tmp\/pip-install-o1r7mv_x\/usb-protocol\/.eggs\/setuptools_scm-6.3.2-py3.8.egg\/setuptools_scm\/integration.py:16: RuntimeWarning:<br>   ERROR: setuptools==44.0.0 is used in combination with setuptools_scm&gt;=6.x<br> Your build configuration is incomplete and previously worked by accident!<br> This happens as setuptools is unable to replace itself when a activated build dependency<br>   requires a more recent setuptools version<br>   (it does not respect \"setuptools&gt;X\" in setup_requires).<br> setuptools&gt;=31 is required for setup.cfg metadata support<br>   setuptools&gt;=42 is required for pyproject.toml configuration support<br> Suggested workarounds if applicable:<br> preinstalling build dependencies like setuptools_scm before running setup.py<br> installing setuptools_scm using the system package manager to ensure consistency<br> migrating from the deprecated setup_requires mechanism to pep517\/518<br>  and using a pyproject.toml to declare build dependencies<br>  which are reliably pre-installed before running the build tools<br> warnings.warn(<br> usage: setup.py [global_opts] cmd1 [cmd1_opts] [cmd2 [cmd2_opts] \u2026]<br>  or: setup.py --help [cmd1 cmd2 \u2026]<br>  or: setup.py --help-commands<br>  or: setup.py cmd --help<br> error: invalid command 'bdist_wheel' <br> <br> ERROR: Failed building wheel for usb-protocol<\/pre>\n\n\n\n<p>Oh ${deity}, this brings back memories of tangling with GNU autotools in the mid 2000s.  Googling the error message finds references mostly to Python 2.7 projects &#8211; so this problem, whatever it is, has existed for a while &#8211; but eventually I figured out that the problem here is that the script is using the systemwide setuptools provided by Ubuntu, and it&#8217;s too old.  Once I realised that pip could download the latest version on demand, I installed it manually into the venv, like so:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">python3 -m venv venv<br>. venv\/bin\/activate<br>pip3 install setuptools --upgrade<\/pre>\n\n\n\n<p>Problem solved?  Well&#8230; no.  When I run the next command from the script:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">pip3 install -r requirements.txt<\/pre>\n\n\n\n<p>I get this:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">ERROR: Command errored out with exit status 1:<br>    command: \/home\/amr\/deca-usb2-audio-interface\/gateware\/venv\/bin\/python3 -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '\"'\"'\/tmp\/pip-install-vvse3nje\/usb-protocol\/setup.py'\"'\"'; <strong>file<\/strong>='\"'\"'\/tmp\/pip-install-vvse3nje\/usb-protocol\/setup.py'\"'\"';f=getattr(tokenize, '\"'\"'open'\"'\"', open)(<strong>file<\/strong>);code=f.read().replace('\"'\"'\\r\\n'\"'\"', '\"'\"'\\n'\"'\"');f.close();exec(compile(code, <strong>file<\/strong>, '\"'\"'exec'\"'\"'))' bdist_wheel -d \/tmp\/pip-wheel-56xus5wz<br>        cwd: \/tmp\/pip-install-vvse3nje\/usb-protocol\/<br>   Complete output (10 lines):<br>   WARNING: The wheel package is not available.<br>   WARNING: The wheel package is not available.<br>   WARNING: The wheel package is not available.<br>   WARNING: The wheel package is not available.<br>   usage: setup.py [global_opts] cmd1 [cmd1_opts] [cmd2 [cmd2_opts] \u2026]<br>      or: setup.py --help [cmd1 cmd2 \u2026]<br>      or: setup.py --help-commands<br>      or: setup.py cmd --help<br> error: invalid command 'bdist_wheel'<br> <br> ERROR: Failed building wheel for usb-protocol<\/pre>\n\n\n\n<p>So I try again, manually installing wheel as well as setuptools, and&#8230;<\/p>\n\n\n\n<p>The installation runs to completion!  Time to celebrate?  Well&#8230; no, not quite yet&#8230;<\/p>\n\n\n\n<p>Rather than build the project directly to a binary, I wanted to use the nmigen scripts to create a project I could open in the Quartus IDE, so I could get a feel for what kind of code nmigen generates, and get an overview of how the project hangs together.  That&#8217;s easy enough:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">python3 deca_usb2_audio_interface.py --dry-run --keep-files<\/pre>\n\n\n\n<p>If all goes as it should, we now have a &#8220;build&#8221; directory, which contains a .qsf file and some verilog files.  No .qpf though, which I&#8217;ll need in order to load the project into the Quartus IDE.  Easy enough to create one, however &#8211; they&#8217;re really simple &#8211; the single line PROJECT_REVISION = &#8220;top&#8221; is sufficient.  So I load this into Quartus Prime Lite 18 and have a go at building it:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">Error (10170): Verilog HDL syntax error at top.v(3434) near text: \"endcase\";  expecting an operand.<\/pre>\n\n\n\n<p>Hmmmm&#8230;. here&#8217;s the construct it&#8217;s complaining about:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"><code>  2'h0:       (* src = \"\/home\/amr\/deca-usb2-audio-interface\/gateware\/venv\/lib\/python3.8\/site-packages\/nmigen_library\/utils\/timer.py:42\" *)<\/code><br><code>       casez (1'h0)<\/code><br><code>       endcase<\/code><\/pre>\n\n\n\n<p>Hmmm &#8211; it seems to object to the empty case statement (maybe a newer version of Quartus will tolerate that?  Or is it a bug in either the project or one of its dependencies?  I don&#8217;t know at this stage.)   It&#8217;s easily fixed with the judicial insertion of &#8220;default: ;&#8221; &#8211; and *then* the project builds, and works!<\/p>\n\n\n\n<p>If I upload the bitstream into the FPGA and then connect the (non-USB-Blaster) USB port to the computer, dmesg tells me this:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">[ 1688.006570] usb 1-2: new high-speed USB device number 3 using ehci-pci<br>[ 1688.163306] usb 1-2: New USB device found, idVendor=1209, idProduct=4711, bcdDevice= 0.01<br>[ 1688.163310] usb 1-2: New USB device strings: Mfr=1, Product=2, SerialNumber=3<br>[ 1688.163312] usb 1-2: Product: DECAface<br>[ 1688.163315] usb 1-2: Manufacturer: OpenAudioGear<br>[ 1688.163317] usb 1-2: SerialNumber: 4711<br>[ 1688.338914] mc: Linux media interface: v0.10<br>[ 1688.382469] usbcore: registered new interface driver snd-usb-audio<\/pre>\n\n\n\n<p>&#8230; and sure enough, I can play audio through the DECA, as a USB soundcard!<\/p>\n\n\n\n<p>Very impressive &#8211; all the more so for being only around 2,500 logic elements in size.  And the main part of the nmigen-based project is under 500 lines of code.  Nmigen, the luna USB project and other related projects are certainly things I want to explore in the near future.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>2021-09-23 A few months ago I bought a couple of the ridiculously cheap DECA boards from Arrow &#8211; they&#8217;re sadly sold out now &#8211; but $37 bought you a MAX10 FPGA with 50,000 LEs, some DDR3 RAM, i2s audio, an &hellip; <a href=\"https:\/\/retroramblings.net\/?p=1718\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4,8,7,14],"tags":[],"class_list":["post-1718","post","type-post","status-publish","format-standard","hentry","category-fpga","category-hardware","category-music","category-rants"],"_links":{"self":[{"href":"https:\/\/retroramblings.net\/index.php?rest_route=\/wp\/v2\/posts\/1718","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/retroramblings.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/retroramblings.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/retroramblings.net\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/retroramblings.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1718"}],"version-history":[{"count":8,"href":"https:\/\/retroramblings.net\/index.php?rest_route=\/wp\/v2\/posts\/1718\/revisions"}],"predecessor-version":[{"id":1727,"href":"https:\/\/retroramblings.net\/index.php?rest_route=\/wp\/v2\/posts\/1718\/revisions\/1727"}],"wp:attachment":[{"href":"https:\/\/retroramblings.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1718"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/retroramblings.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1718"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/retroramblings.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1718"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}