Close
0%
0%

ezsound-6x8 Pi5 multichannel soundcard

The ezsound-6x8 is a high-quality, fully isolated multichannel audio interface for the Raspberry Pi 5

Public Chat
Similar projects worth following
The aim is to bring the world of multichannel audio to Raspberry Pi without costing a fortune. The card, based on the TI PCM3168 chip, provides 6 single-ended inputs and 8 single-ended outputs at 96kHz. The analog sections are completely isolated from the Pi's power supply to minimise the effects of digital noise. The physical layout is designed to provide maximum flexibility for users who want to enclose the Pi and other components (e.g. amplifiers) in a custom case.

The project objectives are:

  • Decent performance for reasonable price (<-90dB THD+N for ~$100AUD parts)
  • 8 channels out, 6+ channels in
  • At least 96kHz sampling rate
  • Full isolation from the Pi - so it will not use the Pi's power supply either.
  • Single-ended inputs/outputs

This is not supposed to be an audiophile device - it is more aimed at value for money. My particular use case is to allow a Pi to act as the brains of a DIY DSP-capable audio system.

The final prototype has the following features:

  • 6 inputs and 8 outputs at 96kHz sample rate
  • Utilises 24.576MHz on-board oscillator for reduced clock jitter
  • Audio chip and analog circuitry is fully isolated from the Raspberry Pi, minimising noise
  • Driver support already included in Raspberry Pi OS and card is auto-detected on boot
  • Main board is compliant to RPi HAT+ specification
  • Power, input and output modules are on a secondary board, and can be easily separated for flexibility in layout
  • Option to mount RCA sockets or 2.54mm dual-row headers for input/output
  • Powered from 9-15V DC supply (either barrel jack or 2.54mm header)

  • From proof-of-concept to final version

    Stephen G04/01/2025 at 05:27 0 comments

    After building the initial prototype, and writing a driver to make it work, I had all the pieces - but it still needed a lot of polishing! Reviewing the existing version, I considered the following:

    • 4-layer boards are quite a lot more expensive
    • the board was never going to fit the HAT form factor no matter how much I "squished" it

    Also, the prototype did not have RCA jacks, and these were something I definitely wanted to include.

    I ended up deciding that having the codec on the hat, and sending the differential inputs/outputs over IDC cables to a separate board with the I/O circuitry was the most reasonable solution. Once I decided on that, it became obvious that the power board should also be attached as a third section of the board.

    Another unexpected advantage of this design is that the VCC+/VCC- power rails for the op-amps don't need to be routed on the codec's board, making a 2-layer board realistic.

    The second prototype was a lot less work - mostly moving sections of the original design onto the 2 separate boards. I did need to rework some sections though to make room for the IDC headers (which take up a lot of room on a HAT!!). It looked very similar to the final version. However, after constructing this version, I found a serious problem. As soon as I powered up the board, the current limiter on my power supply was tripped! There was a short circuit somewhere. By cutting the tracks connecting the 3 modules, and then using jumpers to reconnect them selectively, I was able to narrow it down to the input board. Close inspection revealed that the VCC+ rail was connected to the ground plane.

    After checking my design files, I realised that the files I sent to PCBWay actually had this flaw in them. I suspect I had made a change and did not refill the zones before exporting the files for manufacture. Lesson learned! Anyway, this was pretty easy to fix by using a scalpel to cut the piece of copper in question.

    After that, no more short circuits, but the -6V output from the switching regulator (which is then fed to an LM337 to generate VCC-) was not starting properly - it was locked at 600mV. If I shorted it to GND briefly, then everything worked fine, and I was able to validate that aside from that, the HAT was working perfectly. I've got to admit that I don't know exactly what mechanism causes this problem, but it seemed like delaying the startup of this regulator could be a potential fix. It has an EN pin that I had hardwired to the power input; if I connected it to VCC+ instead, then I figured it would start after the other supply had started.

    In order to test this, I desoldered the regulator in question, bent the EN pin up, resoldered it to the PCB, and soldered magnet wire to the EN pin. This was very fiddly and took me a couple of attempts - the pins are pretty easy to break by mistake. I ended up needing to scavenge a replacement regulator from the previous prototype.  Eventually, I superglued the magnet wire to a nearby capacitor to provide a little bit of strain relief, and then taped it to prevent it snagging... you can see the result in the photo below (the superglue came off later). The a green jumper wire is connected to the magnet wire which goes to the EN pin on the LMR54410, and the yellow jumper is connected to the other magnet wire, which is connected to VCC+ (soldering that one to the MLCC was easy).

     Once I finally got it set up, I quickly learned that connecting EN directly to VCC+ wasn't going to work. A bit of delay was required to allow VCC+ to stabilise before bringing EN high. A good solution to this type of problem is a voltage supervisor IC. It simply waits until its input is above a threshold voltage for a specific amount of time, then brings its output high. In fact, the codec board already included one to keep the chip disabled until VDD is stable. I identified a part (TLV809EA46)...

    Read more »

  • Exploring sound on Linux

    Stephen G03/22/2025 at 05:20 0 comments

    This log will focus on the journey I took in figuring out how to write a driver for the soundcard. I will not go into minute detail, but I will summarise the things that I learnt which might be useful for others. When implementing a soundcard for something like the RPi, you will need to become famliiar with the Linux ASoC framework. This framework allows you to describe the soundcard architecture - what components there are, the characteristics of the various components, and how they're connected - and it takes care of interfacing this with ALSA (the Linux sound architecture).

    Essentially, the soundcard driver needs to tell ASoC:

    • What CPU audio interface you will use (the 'cpu' component)
    • What codecs are present (the 'codec' component)
    • What audio links exist (connecting the cpus and codecs to each other)
    • The 'other stuff' like the various power domains, clocks, and so forth

    There is very good documentation in the kernel docs, but it can be confusing when you aren't familiar with the terminology.

    Another thing to be aware of is that there are a couple of generic soundcard drivers available that let you define a soundcard entirely in the device tree. The generic driver will read the definition from the device tree, and then make the appropriate calls to ASoC. This avoids the need to distribute a driver at all, and is actually sufficient for a lot of cards.

    The generic driver options are as follows:

    • simple-card : This allows you to create cards where each audio link goes from 1 CPU to 1 codec.
    • audio-graph-card : I didn't use this much, but it appears to be a reimplementation of the simple-card capabilities using graphs to describe the links
    • audio-graph-card2: This is a graph-based generic driver which is extremely powerful and allows you desribe N:N audio links. See the documentation for examples.

    You can see examples of RPi soundcard drivers in sound/soc/bcm under the Linux kernel tree, and the various device tree overlays in arch/arm64/boot/dts/overlays. (Don't be confused by "rpi-simple-soundcard" - this is a single driver that handles several different RPi soundcards and has nothing to do with the "simple-card" generic driver).

    In the ezsound device tree overlay, you'll see:

    1. Setting the pin configuration for both of the RPi5's I2S controllers. One is hard-wired as clock producer, and the other is hard-wired as clock consumer, and they use the same pins. It's up to you to use the appropriate one. By default, only 1 set of DIN/DOUT pins is active - this enables the rest.
    2. Usage of simple-audio-card to create two DAI links, one for playback (DAC) and one for capture (ADC). Both have the RPi's I2S clock consumer block as the CPU end of the link. On the codec end, both are configured as clock producer with a Mclk/Fs ration of 256. Note that there is only one physical clock pin on the RPi5, which is connected to both the ADC and DAC clock pins on the PCM3168A. So this seems like we will have two clock producers connected together - a recipe for disaster. More on this below.
    3. The PCM3168A is configured on the I2C bus 1 at address 0x45, with a 24.576MHz sysclk. Note the "force-dac-cons" parameter.

    In order to make this work, the PCM3168A needs either the DAC or ADC (but not both) configured as clock producer, and the other configured as clock consumer.

    The problem is, when I started working on this, ASoC audio links (or DAI links as they are formally known) were either "CPU producer" or "codec producer", and if you had them set as "codec producer", then all codecs would be set as producer. This means that an audio link with 1 CPU, 2 codecs, with one of the codecs as clock producer cannot be configured properly. You can see here that ASoC has been enhanced in Linux 6.14 to remove this limitation.

    However, Linux 6.14 is far away from being adopted by Raspberry Pi - they are currently in the process of moving to 6.12. So a workaround is needed. That's where the "force-dac-cons" parameter...

    Read more »

  • Prototype A: Proof-of-concept

    Stephen G03/19/2025 at 11:42 0 comments

    The aim for the initial prototype was to simply get something working. This would verify that the Pi5's I2S interface didn't have any weird limitations and allow me to start learning about Linux sound and device trees (in my previous stereo ADC, I had just copied someone else's device tree overlay). Therefore, the design did not really consider form factor at all.

    The first thing was to choose a codec chip. I selected TI's PCM3168 because the datasheet was more detailed than the one for the other main candidate, the AD1934, and the Linux driver support was much more complete. Its differential inputs and outputs meant that I'd need to include lots of SE/diff conversion circuitry and there was no chance of it fitting on a HAT, but I figured this was OK since the RCA connectors would not be able to be on the HAT anyway. I feel I made the right choice.

    Power design was something I spent quite a bit of time on. I needed 3.3V and 5V for the digital and analog supplies of the PCM3168. But the question was, what voltages should the op-amp rails run at, and what intermediate voltages would I need to generate in order to get those? What is the right combination of switching vs. linear regulators? What about noise performance and current capacity? This was probably the part of the hardware side where I had to do the most actual engineering.

    I ended up settling on using two identical switching ICs, one of them configured in "upside-down" mode, to generate +/- 6V. In the initial prototype, this section was on a separate board. These supply rails were then fed to 4 separate linear regulators, which generate the codec supplies (5V, 3.3V) and the op-amp rails (5.5V, -3.3V). I felt my choices were a good balance, maximising the op-amp swing while leaving sufficient signal headroom, not generating too much heat, and with pretty good noise rejection.

    Because I needed to route power rails all over the place, I ended up designing a 4-layer board, which was also a first for me. I reached out to a contact at PCBWay who had sponsored a previous project and they kindly agreed to support the manufacture of this first prototype. They even paid shipping! Massive thanks for that.

    After ordering the boards and parts in late Feb, construction didn't have any huge problems (except the usual solder bridges) but it was time-consuming and the prototypes were ready for testing in late April. Unfortunately my Pi5 still hadn't arrived! Once it finally showed up, I could not detect the codec chip over I2C. Life got busy for a little while and when I picked it back up in August, I figured out that I'd omitted I2C pullups on the codec side of the isolators. Fixing that took another couple of weeks (nothing happens fast when you're doing it on weekends), and then in mid-September I had the first signs of life from the chip! It might seem like this was taking forever, but I was also spending time on learning the software side of things at this point. Once the chip was talking on I2C, I was able to play 8 channels of audio via the I2S interface and verify that they were working, which was very exciting!

    The input side was a little trickier - from my notes at the time: "After a couple of mods I just successfully recorded some audio on one of the channels. I had put some termination resistors in, but I hadn't fully thought through how the signals would flow and they ended up just interfering. The board is small enough that replacing them with zero ohms worked fine. I also made a boo-boo with some capacitors that prevented the ADC reference voltage from getting above GND."

    On Nov 20, 2024, I noted: "Today I managed to successfully run all channels simultaneously in loopback mode (jumpers going from the outputs to the inputs) and it worked perfectly!"

    Concept was proved! What remained:

    • Serious thinking about form factor and physical layout
    • Figuring out how to create an actual soundcard driver that interfaces...
    Read more »

  • In the beginning...

    Stephen G03/18/2025 at 11:51 0 comments

    This is the first in a series of entries where I will walk through the journey of taking the ezsound 6x8 soundcard from idea to reality. This post will be more about the background and design goals, so if you're interested in juicy build details, perhaps check out subsequent posts.

    The project was initiated because I ran into a very specific problem. During COVID I needed something to keep me sane, so I began building a DIY audio system. I wasn't really keen on analog crossovers because they seemed, well, a bit too boring, so I decided to build 3-way speakers with digital crossovers, and the concept of a Raspberry Pi-powered system started to seem more and more attractive. I bought a SupTronics X7000 board which took the HDMI output from the Pi and split the 8 channels of audio out to 4 stereo amplifiers. I developed (with surprisingly little effort) a DIY stereo ADC HAT based on the CS5341 that I used to bring audio in, and then used the fantastic CamillaDSP software to split out the various frequencies and send them to the amplifiers. It was working well. Unfortunately, there was a strange bug where occasionally, a buffer overrun would switch the channel order. Sometimes it would work fine for several hours, then get triggered in the middle of a movie resulting in very poor-quality audio (since the wrong frequencies were going to the wrong speakers). Sometimes a restart of CamillaDSP would fix it, sometimes not (I even modified the CamillaDSP source so that it would restart on a buffer overflow instead of just resuming the stream... this worked - sometimes). My kids were happy for me to use the system, but whenever it happened to them, they'd switch back to the TV speakers to avoid it happening again. Fair enough, I guess.

    After chasing the bug for a little while, I gave up and started looking for alternatives. I soon realised that there weren't any that were terribly satisfying. I had a Pi4, and it can only output multichannel audio via HDMI (the I2S interface is stereo). The board that I was currently using was no longer sold (meaning that if my current one broke, I was going to be stuck), and I'd read reports of other HDMI extractors suffering similar channel swapping issues. A USB soundcard wouldn't fit the bill, because the soundcard would need to be on the outside of my enclosure in order to plug into the Pi's USB port, but the audio needed to get to the amplifiers which are inside the enclosure. If only there was a multichannel audio HAT, it would solve all of these problems!

    I should mention that I did run across the Audioinjector Octo. This was a kickstarter project that did deliver a multichannel (8 outputs) soundcard for the Pi, by running the I2S interface 4 times faster and then using an FPGA to unpack the individual channels. Respect to flatmax for achieving this, but it was no longer available.

    Around this time, the Pi5 was released, and I noticed it included (theoretically) 8-channel I2S. However, asking on the Pi forums and diyaudio.com, it appeared that nobody had actually witnessed it working. But it got me thinking - if I could develop a stereo ADC HAT relatively easily, maybe I could do something a little more challenging and develop a full soundcard with multiple inputs and outputs? However, there were quite a few challenges:

    • Nobody really knows whether the Pi5 I2S interface actually works with 8 channels and the documentation was limited to a bullet point saying it exists. Who knows...
    • I didn't have a Pi5, and didn't really want one until I knew the I2S interface worked
    • I didn't know a thing about sound on Linux

    I kept an eye out and eventually in late Jan 2024, the user mdsimon2 on audiosciencereview.com announced that he'd successfully been sending 8 channels of input from an HDMI extractor to the RPi5 over I2S (with technical guidance from user phofman - you can find a lot more information on RPi + CamillaDSP here). That...

    Read more »

View all 4 project logs

Enjoy this project?

Share

Discussions

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates