Sunday, May 2, 2021

ESP32-Radio (Part 1.5)

Introduction

It's been quite a long time since my last post and that is because I felt unreasonably tired lately, which might have been related to my work. In any case I've had a lot of progress with this project even if I was stuck with very basic, vary fundamental and very annoying issues for some time. Most of these issues are related to the basic things discussed in part one, so I'm writing this part "one and a half" before part two. I've also learned quite a few things related to the FreeRTOS that is included in the ESP-IDF. So let's discuss these few little things.

Buffer overflow

As discussed in part 1, the radio server seems to send data at a much faster rate than it's supposed to right after the connection has been established. I suspect this is done so that the client can fill the audio buffer quickly and start playing the audio. Without any check the audio buffer in ESP32 would fill up quickly and overflow while also making annoying noises. I fixed this issue by making the code loop until there is some free space in the buffer. This works "nicely" since the ESP32 has two cores and the other core can run the task that is responsible for sending the audio data to the decoder chip (among others).

At this point I think that is the worst way to solve this issue. The problem is that the code is simply stuck without the possibility to run any other code on that core. The correct way would be to use FreeRTOS Stream Buffers which would allow task switching in case the buffer is full. Using this would however require quite a lot of rewriting, which I didn't (yet) want to do. Eventually I realized that simply using vTaskDelay (in the loop) with a minimum time, would basically do the same thing. The code would check whether the buffer is full and issue this wait statement if it is. This in turn would allow other tasks to run on this same core instead of just running NOPs. Before this change the device definitely had some hiccups from time to time, but this change significantly improved performance and the issues are now gone.

VS1053b MIDI

As discussed in the first part, the VS1053b board from eBay has a design flaw, where the IOs are not pulled down as they are supposed to (as shown in the datasheet). This is related to the fact that this board is possibly the shittiest design that I have ever acquired from eBay. As explained here, "most modules will start in MIDI mode". There is also a link that points here. I originally failed to understand the fact that after making these "few register writes", it is necessary to make a soft reset so that the chip can read the state of the pins at boot.

Interestingly the device worked quite fine with my faulty code for a long while but then it simply stopped working. The funny part here is that when the device boots into MIDI mode, the AUDATA is configured to 44101 (which is okay for most servers and means 44100 Hz sampling rate and stereo mode) and the DREQ pin is high, which means that the device is constantly draining data and not playing anything.. However the latter link has a picture of pins that have to be physically connected (circled in green in the picture below) for the device to boot properly without any software fixes. I should have used the physical fix right from the start, but instead I wasted a lot of time making workarounds to detect the "stuck device" and rebooting it. That was a huge waste of time, cannot recommend. However here is the link to the original explanation right from the manufacturers of the chip.

VS1053b Board Buzzing

As I've explained in the first part, the board that I have, was making a very annoying and rather loud buzzing sound. The sound was coming from the board itself and couldn't be heard in the audio output. I spent quite some time poking around the VS1053b board without any luck. I also tried measuring voltages on the board, again without any luck. I tried to live with but after some time I was too annoyed again. It almost gave me headaches since it was so loud. Then I remembered how these things should be debugged: simply by taking a cap and poking it in different places. After some poking the buzzing suddenly stopped. After two months of ~constant buzzing it simply stopped (I had it connected to a USB port and thus it was on all the time my PC was on, just to see that it doesn't crash or disconnect).

And here's the explanation. The main output cap (C1) of the 1V8 regulator (U3, the core voltage) was located quite far away from the regulator. The regulator in question is AMS1117 and according to some datasheet it requires an insane 22 microfarad output capacitor. This capacitor should obviously be as close to the regulator as possible. Instead it's a few centimetres away and the connecting tracks are routed god knows where (shown in red and purple in the picture below). There is however a 100 nanofarad capacitor (C18) right next to the regulator, which, I suspect, was simply faulty in some way. After I've desoldered both 100n capacitors (3V3 and 1V8) and replaced them with 4.7 microfarad capacitors (C18 and C17 in the picture), the board has not made any sound (except for the audio output of course).


VS1053b evaluation board from eBay

I tried to understand this later on with the help of an oscilloscope without any luck. My final conclusion is that the original capacitor C18 in the picture above was faulty, since the board made no audible sound even without anything soldered in its place.

I've also acquired a second board to have just in case, and that board was even worse. It had the VS1003 chip instead of VS1053 and had a 2.5 V regulator instead of 1.8 V one. This part needs clarification. For the VS1053b the voltage ranges are 2.5 .. 3.6 V for AVDD, 1.7 .. 1.85 V for CVDD and 1.8 .. 3.6 V for IOVDD. So two regulators (3.3 V and 1.8 V) are enough for the VS1053b. For VS1003 however, the respective voltages are 2.6 .. 2.85 V for AVDD, 2.4 .. 2.85 for CVDD and CVDD-0.6 .. 3.6 V for IOVDD. Since the board looks the same as in the picture above, I assume that on this board AVDD is connected to 3.3 V. And the question is why would you do that? Absolute maximum ratings exist for a reason. Picture of the board is shown below.


VS1003 evaluation board from eBay

Perhaps less surprisingly this board didn't work correctly. It usually started okay and then the audio just faded out after some time of playing. I tried to debug it for a while and then simply gave up because the board is clearly not worth it.

Header issues

As I've explained in the first part, the server will send an HTTP header after the connection has been made. The new thing is that this header might vary a bit between different servers. This might be an issue, because I've only tried this with exactly two different servers and found three different issues. Here are the issues that I've encountered until now.

One server doesn't seem to send the sample rate of the audio at all. This is not an issue, since the sample rate can be read from the decoder chip and more specifically the AUDATA register. The value should be adjusted simply by (AUDATA >> 1) * 2 to get the actual value (to lose the stereo bit).

One server sends some garbage instead of the stream name. This is very annoying. However it can be easily solved by not using this value. The name of the radio station can simply be hard-coded with the URL address of the server in the device. I had an idea of fetching some channel list automagically for example from SHOUTcast API, but that's for another time.

One of the servers seems to use "content-type" as the tag while another uses "Content-Type". Solution for this is simply to use tolower function before trying to detect the tag.

Prototyping issues

This prototyping phase has lasted quite long for this project and the reason is that I want to try as much of the final implementation with it as possible. By as much as possible I mean the display and the buttons & rotary encoder. Since the pins of the ESP32 can be assigned quite freely, I can change the schematic based on the board design, to make the routing as simple as possible. The prototype can then be easily reconfigured to test the new connections before ordering the PCBs.

However there are a few issues related to the prototype. The worst issue is that because of the long wires, the device will easily pick up noise. I suppose it's not very dangerous, but suddenly hearing the audio at the maximum volume is certainly not fun. I've noticed this already at my desk and then I definitely noticed this when testing at the location where the end device is supposed to be used. Basically switching a noisy lamp or a power supply on or off will make the device output audio at full volume and also somehow garbled. Luckily the volume goes to the exact maximum, so it's very easy to detect as an error case.

I've concluded that this is not very good even for a prototype. So with my newly knowledge of FreeRTOS, I quickly made task that regularly checks whether the volume is at maximum and lowers it to some sensible level if it is. In retrospect, this fix had one of the best effect / effort ratios of all the things that I've made for this project.. Unfortunately the audio is still garbled so this fix doesn't solve that. I suppose it would require restarting the audio decoder. That would then require logic for finding the beginning of the next audio packet in the stream, or it would simply glitch for a while until the decoder gets the next header and recovers. In any case this should not be an issue with the final design and until then at least I don't need to hurt my ears.

Another issue related to the prototype is that some wires usually end up being near/above the WiFi antenna of the ESP32. This seems to be an issue because it introduces some noticeable noise in the audio output of the device. This is rather annoying because I can clearly hear it whenever there is a silent moment in the music. Interestingly there are no audio cables near the WiFi antenna, which means that the voltage regulation of the audio board is not very good. However it's enough to just insert some item between the antenna and the wires to get rid of this problem. For example a USB memory stick is very much enough. The signal strength will obviously be worse after this, but at least there is no noise in the audio whatsoever. This "fix" is okay for the prototype and should not be an issue with the final design. This is one good reason to follow the esp32 hardware design guidelines. :)

Final Words

I can only say that a lot of lessons were learned here. A simple RTFM can be applied here of course but it seems that FreeRTOS contains quite a few new things for me to learn. Also the issue with MIDI was just a very annoying mistake. The rest are simply adopting to the environment.

No comments:

Post a Comment

Internet of Crosstrainers, part 2

Introduction As mentioned in the original post here , there were some issues in the described implementation. I had some difficulties to fin...