Tuesday, February 2, 2016

Raspberry Pi 2 and USBStreamer

Some time ago I got a Raspberry Pi 2 board and was hoping it would be a better headless player than BeagleBone black. Probably some people could get good results, but not me.
I tried different images - plain Debian wheezy and jessie, Volumio, RuneAudio, and MusicBox.
All of them work well playing over HDMI but none could play 192K flac on my USBStreamer so I started to believe RPi2 still has serious issues with USB hardware.
I regret of time I wasted but I still learned something new going through the process.
So BeagleBone goes back into it's original place...

But by the way a couple of impressions I got during my 'testing'.

  • Plain Debian Jessie is the winner in terms of boot time. But at the moment I tried it I got problems with autofs NFS mounts and it seems to be a known issue with rpcbind.
  • Volumio doesn't see any changes on USB bus and has the longest boot time
  • RuneAudio we interface feels the most responsive
  • System update kills both RuneAudio and Volumio.
    That's very unfortunate because if I don't update all the packages the system can eventually break after I install other software that require newer dependencies. For example, when I tried to install build-essential package on Volumio 1.55 it started to upgrade perl and php! It looked like a joke actually. Another example is when I installed NodeJS on RuneAudio it upgraded ncurses to a newer version which broke some commands. Luckily a simple symlink helped older packages to find the newer library.

Saturday, December 5, 2015

The current state of the project

I had my first amplifier test run almost two years ago so wanted to share the current state of the project.



Still far from perfect and definitely not final.
I just put it into a case of a useless Onkyo surround processor. The idea was to test if the amp fits into a slim case and do not overheat without any active cooling. It seems it does well so I'll need a nicer case soon... After I finish my migration to Raspberry, of course ;)

Saturday, November 21, 2015

Raspberry I2C bus scanner

The most important thing I need to solve while migrating from BeagleBone to Raspberry Pi is how would I control my PWM modulator via I2C bus.
My Raspbian didn't have a /dev/i2c* devices out of the box so I can't just copy my python scripts to Pi. That is not actually a problem and can be fixed easily.
But what about a new challenge?
So I decided to go a level lower and control my amplifier via BCM 2835 library by Mike McCauley from a C++ program. Never wrote a C++ Linux program before so why not?

I must say there is no fun to use something like nano or vim and plain gcc. I personally not a masochist so I would stay with python if I had to do that 'traditional' way. But luckily for us, Oracle has NetBeans IDE that makes it possible to program and debug any Linux device remotely. 
That's a different story how to make it work and how to elevate permissions to debug a program that interacts with hardware, but it is easy to google out.

Since I didn't want to take apart my only working amplifier I started with a random I2C device I had on hands - a little board that has DS1307 RTC clock and 24C32 EEPROM,

Also as I mentioned before, my Linux didn't have I2C bus enabled so I couldn't use i2cdetect tool. As a result now I have my own I2C bus tester.
So here it is on GitHub.

And for the setup I have
the output is
        +0      +1      +2      +3      +4      +5      +6      +7      +8      +9      +a      +b      +c      +d      +e      +f
0       .       .       .       .       .       .       .       .       .       .       .       .       .       .       .       .
10      .       .       .       .       .       .       .       .       .       .       .       .       .       .       .       .
20      .       .       .       .       .       .       .       .       .       .       .       .       .       .       .       .
30      .       .       .       .       .       .       .       .       .       .       .       .       .       .       .       .
40      .       .       .       .       .       .       .       .       .       .       .       .       .       .       .       .
50      O       .       .       .       .       .       .       .       .       .       .       .       .       .       .       .
60      .       .       .       .       .       .       .       .       O       .       .       .       .       .       .       .
so I clearly see two devices on addresses 0x50 and 0x68.

Next step is to rewrite and simplify my python scripts in C++. And use them from a NodeJS app.
But stop! Here a legitimate question pops up: why bother with C++ when I could use existing Node I2C libraries? 
The answer is simple: I already fried my tweeters other day and I wish my speakers to live longer. So I can't trust an asynchronous Node process that calls python scripts whenever I want to access the I2C bus. It is not about the speed, the speed might be good enough to control the volume or mute/unmute the PWM. I just don't want Node event loop to be in control of timings. Probably it sounds old-stylish but I believe the lower you go controlling hardware the better.
I dream about a character device driver but it seems too complex for me at the moment because I'm a total newbie in Linux programming. So let's see what I can come up with later. 


Sunday, September 6, 2015

Time to switch to Raspberry Pi?

Raspberry Pi Model 2 looks cool for its price. Better than a single core BeagleBone Black I'm using.
It has 4 USB ports so I can try to connect my USB audio along with WiFi dongle.
Why not to upgrade?

There are lots of distributions out there but I need a stable one with at least two features:
1. MPD that can play via USB Streamer (requires working USB Class 2 Audio mode)
2. Working I2C bus library

So I bought my new toy and started to slowly work on that...

So far I have MPD playing through HDMI, that's a good beginning

Saturday, July 25, 2015

A real-life NodeJS application

After I resoldered prematurely died amplifier chips and put it all together again I decided to take some easy steps to help my amplifier live longer.
The one of easy ways I see is to unmute it when MPD starts playing and mute when it stops or pauses. That will shut down PWM modulation and basically turn off the power stage so I don't need to manually turn it on or off,

That's seems to be a good job for NodeJS!
Node works just fine on Linux boards like BeagleBone or Raspberry Pi and there are lots of success stories how folks do all kinds of stuff.
No need to invent a wheel and there is a neat Node mpd client ready to use,

I already have some python scripts to control my PWM modulator so the idea is to use Node to invoke them when needed. Sounds easy.

So here my first working Node application. It's not polished but just a simple proof of concept.

var fs = require('fs');
var exec = require('child_process').exec;
var mpdlib = require('mpd'), cmd = mpdlib.cmd;

// hardcoded paths to mute & unmute scripts
var cmd_play = "python /root/cr/unmute.py";
var cmd_stop = "python /root/cr/mute.py";
var errorMonitorInterval = 600000;

var refreshMPD = function() {
   client.sendCommand(cmd("status", []), function(err, msg) {
     if (err) console.log(err);
  if (msg) {
   var data = mpdlib.parseKeyValueMessage(msg);
   console.log(data.state);
   if(data.state == "play"){
    execute(cmd_play, console.log);
   } else if (data.state == "stop" || data.state == "pause") {
    execute(cmd_stop, console.log);
   };
  }
   });
 };

// if something wrong happens I don't want it to flood my log file
var firstErrDate, lastErrMessage = "", errCount = 0;
setInterval(function () { 
 if(errCount>1){
  var date = new Date();
  d = date.toLocaleString();
  console.log("[" + d + "]:\t" + "Last error happend " 
  + errCount + " times in the last " 
  + Math.round((date - firstErrDate) / 60000) + " minutes.");
 }
}, errorMonitorInterval);

var logError = function(err, when){
 var date = new Date();
 d = date.toLocaleString();
 
 var message = err.message || err;
 if(!firstErrDate || lastErrMessage != message){
  if(errCount > 1){
   console.log("[" + d + "]:\t" + message + " happend " + errCount + " times so far."); 
  }
  firstErrDate = date;
  lastErrMessage = message;
  errCount = 1;
  console.log("[" + d + "]:\t" + message + " when " + when);
 } 
 else{  
  errCount++;
 }
}

var execute = function(command, callback){
 try{
     exec(command, function(error, stdout, stderr){ 
      if(error){
       logError(error, "executing \'" + command + "\'");
       callback(error.name); 
      }
      else {
       callback(stdout); 
      }
     });
 }
 catch(err){
  logError(err, "executing \'" + command + "\'");
  callback(err.name);
 }
};

var getDate = function(){
 var d = new Date();
 return d.getMonth() + 1 + "/" + d.getDate() + "/" 
  + d.getFullYear() + " " + d.getHours() + ":" 
  + d.getMinutes() + ":" + d.getSeconds();
};

//===================================
var client = mpdlib.connect({
  port: 6600,
  host: "localhost",
});

client.on("system-player", refreshMPD);
client.on("system", function(name) {
 if(name == "mixer") refreshMPD();
});
client.on("ready", refreshMPD);

The only problem I found with running NodeJS on BBB is that sometimes music has drop-offs. But it is easy to fix as we can lower the priority with nice command. Like:
>nice node amp.js

and music just plays. And amplifier stays ice cold when music is off.
Sweet!

Thursday, April 16, 2015

How to fry TAS5631B. Guaranteed.

The happiness couldn't last forever and I found a pretty much stable way to make a toast out of TAS5631B,
Here is my simple recipe:

  • Connect VDD (+12) to the board
  • Short any single speaker output to the GND
  • Connect PVDD (+50)
  • Voila, /SD and READY outputs are always low and can't be cleared via /RESET or power cycle.
  • Cry and order a new chip

Datasheet says "The TAS5631B does not require a power-up sequence." and "it is recommended to hold RESET in a low state while powering up the device". Not sure holding down RESET can prevent mosfets from a premature death.

How could I find it out?

Well, that was my bad. I connected the power supply with 3-wire power cable. For some (probably good) reason power supply has the Earth electrically connected with the output GND.
As you may know, most scopes have the negative probe connected to Earth.

I fried two of my boards while I figured out why my scope doesn't show any signal...

I'm wondering now if there any way to test for a grounded output before applying PVDD.

Saturday, December 20, 2014

Got it together but not for a while

Finally we settled in our new house. Can't say I'm done with our new IKEA kitchen but it is usable now. So it's time to have some hobby fun and play with my amp and speakers.

Finally I put all six channels together with BeagleBone Black and two switching power supplies - one for power amp and one for the BBB. Also I got very sexy VFD display from eBay for a very good price so I'd like it to show some useful information very soon.

Standard Debian seems to be a good choice but I found two problems with it (updates a pretty frequent so the latest one may work better):
1. it can't find my USBStreamer if it was reconnected
2. MPD playback has noticeable drops.
Then I found a great distribution - Voyage MPD. It is outdated but it doesn't have these two problems I mentioned above. But this distribution would not work for folks who want to use HDMI output - HDMI itself works but HDMI audio output is not available.

So I mounted my NAS, set it all up and finally got my music played without drops and pops!

But my happiness did not last for long. I wanted more. So I tried to put some coefficients into loudness biquad... And got my tweeters fried in a faction of a second. As well as one TAS5631B chip.  Woofers and midranges survived.
So I got a very good lesson - always disconnect speakers when you play with biquads! And use a scope first!