Ethernet Audio library and web server in one project(?)

Status
Not open for further replies.

turbo2ltr

Active member
Before I go down the rabbit hole, I figured I'd ask....

Are there any technical limitations of having a small web server running parallel to the Ethernet Audio library?

The web server example works fine on the hardware. But when I try to integrate it into my ethernet audio project, the setup works (server.begin()), but the first time it calls
Code:
EthernetClient client = server.available();
the teensy crashes.

Aside from letting the EthernetAudio handle setting up the SPI, MAC and IP, my code is copied and pasted from the webserver example. I recognize the way the example is written, it's blocking so I would rewrite it to keep loop times low. But it's not getting past the first line.
 
Correction, it actually loops about 80 times before it crashes.

It crashes in socket.cpp EthernetClass::socketStatus()

Code:
uint8_t status = W5100.readSnSR(s);

I don't see a function called that so I don't know were else to go.

Going to assume this is some SPI collision again. uhg.
 
I was able to get this to work intermittently by NOT calling
Code:
EthernetClient client = server.available();
every loop, but every 1000 loops. Now I know that's a terrible idea but it was just a test.
It is still very flaky. Most of the time it still crashes shortly after boot.
Other times it goes for a while. But while the few times it doesn't crash right away, it will serve the web page, but it won't close the connection.

You can see the two sockets..
Code:
Socket#0:0x22 8888 D:10.0.0.255(8888)
Socket#1:0x14 80 D:0.0.0.0(0)


I think I just need to take a deep dive into how the ethernet and ethernetaudio library work. I need to figure out what is clashing. People wonder why I always tend to write everything from scratch whenever possible. Libraries are great time savers, until they aren't. Sure it would take me a long time to write my own library, but at least then I'd know how it works when something breaks. It takes just about as long to troubleshoot someone else's library...

Back to work.
 
@wwatson did a USBHost lib for USB using a dongle to wired ethernet that worked well. Not sure if that experience relates?

That example used the TeensyThreads to periodically call some check polling/update funcs and over calling that was bad. That was on the USB side of things and may not directly relate ... so just FYI. The change that made it work there was this well named '#ifdef HACKED' add I tried and found to work in that code that limited loop cycles per time slice:
Code:
    #ifdef HACKED
    cc++;
    if ( cc > 20 ) {
      cc=0;
      threads.yield();
    }
    #endif

Anything called in loop() - depending on the Teensy and what else happens each loop cycle can call 50K to 5+ million times per second if not gated. So rate limiting calls to some functions can be important - saves cycles and some things go bad when over polled.
 
Any chance you might share a small but complete program to demonstrate the problem?

If no code is posted here to reproduce the problem, I'm afraid the reality is this issue will never be investigated or fixed. This description of the problem is not enough. A complete program which reproduces the problem is needed.
 
Hi,

Unfortunately the Ethernet code, and particularly the WIZ routines, are not re-entrant and particularly do not fare well if any (software or hardware) interrupt-driven code tries to use the same SPI channel.

Try the alternate (newer) code in https://github.com/palmerr23/audio - this is an informal dev branch, which is more stable when interacting with other audio objects than the main branch. I'll merge them when I get back to the Ethernet Audio project, which is undergoing a major re-fit to be more compatible with other protocols (specifically V-BAN).

Ethernet Audio relies on one of the other objects having update_responsibility - that is triggering the update() cycle for all objects, as the Ethernet code is not (currently) interrupt driven.

You could try servicing web requests within an audio library-friendly object (i.e. called in the update() cycle), which calls each object's update() sequentially, thus avoiding SPI transaction conflicts. Use the AudioControl.h template and add the code servicing TCP requests during the update() cycle - to avoid communications with the WIZ chip being disturbed, mid-transaction.
 
You could try servicing web requests within an audio library-friendly object

Thank you. I had tried the newer library and after several hours I could not get it to work within my project (not blaming the library). I went back to my modified library and was able to get this idea working in an hour. Thanks!
 
I assume there is some limit to how much time the update routine can take and not affect audio?
Also, is update run regardless of the main loop speed? i.e. if I have something blocking in the main loop, does that affect the updates? Obviously I try not to block anything but just trying to understand.
 
Yep, it needs to be completed well within a 2.9 mS window (44.1KHz / 128 samples) and leave plenty of time for other processing.

https://www.pjrc.com/teensy/td_libs_AudioProcessorUsage.html

update() is triggered by a software interrupt, so it will run unless interrupts are off, even if a the main loop is blocking. So, don't run anything that calls the SPI interface that is used by the WIZNET module from the main loop, because the update() interrupt triggers a whole lot of (asynchronous to the main loop) WIZNET SPI traffic.

https://www.pjrc.com/teensy/td_libs_AudioNewObjects.html
 
Thanks for the info. I've somehow missed those pages thus far.

I've found the built in ethernet library does a rather poor job and managing multiple connections. Particularly the server.available() code that is written in a way that handles requests sequentially instead of asynchronously with no control over which socket is being serviced. Most of the server examples out there seem to assume that you will only get one request, and reply right away, but because of the time window in this environment, I made a state machine that would allow me to decouple the receiving and processing request from generating and sending the reply. And now there is a state machine for each socket that handles parsing of the request, and waits for the sketch to generate the reply, so the various sockets get handled in parallel. Seems to be working well though still not a complete solution. But previously if I refreshed the page a lot, the audio would have some artifacts but now I can refresh as fast as I can and no audio artifacts. Not that I expect that kind of traffic at all.

Coming along slowly but surely. Thanks for the help!
 
Status
Not open for further replies.
Back
Top