0

Working on an IoT project.
Environment:

  • Adafruit Feather M4 Express
  • Adafruit MusicMaker FeatherWing (amplified, this is a VS1053 at heart)
  • Silicognition PoE FeatherWing (electrically compatible with the Adafruit Ethernet FeatherWing)
  • PlatformIO with Visual Studio Code on a Mac (all libraries are up-to-date)

The Problem:
I can get either the Ethernet to work or the MusicMaker to work, but not both at the same time.
There are no errors during initialization, they just don't work.

Specifically, the MusicMaker's sineTest() method doesn't generate any sound if Ethernet has been initialized. Likewise, the Ethernet client's connect() method is unable to connect if the MusicMaker is initialized. Both methods work fine if the other device hasn't been initialized.

Feather Pins:

Purpose                    Pin
-------------------------- ---
VS1053 Chip select           6
VS1053 Data/command select  10
VS1053 Data request          9
SD Card Chip select          5
Ethernet Chip select        14

Note that I'm not currently using the SD card and haven't called its begin() method.
Note also that the Ethernet chip select is on a non-standard pin because the default conflicts with the VS1053 data/command select.

Also, the PoE FeatherWing has an EEPROM on it with a unique MAC address and reading this works fine.

One other note: I thought that I had this combination working in an earlier prototype a few months ago, but that may have been with the Feather 32U4.

TIA.

The prototype code:

#include <Arduino.h>
#include <Adafruit_VS1053.h>
#include <Ethernet.h>
#include <IPAddress.h>
#include <SPI.h>
#include <Wire.h>


//
// Pins for the Ethernet and MusicMaker FeatherWings.
// NOTE: These definitions assume a Feather M4 Express with a PoE FeatherWing
//       modified to have its chip select on pin 14 because the default conflicts
//       with the MusicMaker's DCS pin.
//
#define VS1053_CS       6     // VS1053 chip select pin (output)
#define VS1053_DCS     10     // VS1053 Data/command select pin (output)
#define SD_CARD_CS      5     // Card chip select pin
#define VS1053_DREQ     9     // VS1053 Data request, ideally an Interrupt pin
#define ETHERNET_CS    14     // Ethernet chip select pin. Note that this is custom because the default conflicts with VS1053_DCS.

//
// PoE FeatherWing.
//
#define MAC_EEPROM_I2C_ADDRESS      0x50  // I2C address of the 24AA02E48 EEPROM chip that contains our MAC address (on the PoE FeatherWing).
#define MAC_EEPROM_REGISTER         0xFA  // Register within the 24AA02E48 that contains the first byte of our MAC address.

#define HANG      while( true ){ delay( 10 ); }
IPAddress         host = { 172, 24, 110, 1 };
uint16_t          port = 8000;
const char*       path = "/sounds/DingDong.mp3";
Adafruit_VS1053   player{ Adafruit_VS1053( -1, VS1053_CS, VS1053_DCS, VS1053_DREQ ) };
EthernetClient    client;
uint8_t           mp3Buf[VS1053_DATABUFFERLEN];
uint32_t          contentLength;
byte              macAddress[6]{};

uint32_t          beginRequest();
void              readMacAddress( byte* );

void setup()
{
  Serial.begin( 115200 );
  while( !Serial ){ delay( 10 ); }
  Serial.println( "MusicMaker/Ethernet Prototype" );

  Wire.begin();

  Ethernet.init( ETHERNET_CS );
  readMacAddress( macAddress );
  if( !Ethernet.begin( macAddress ))
  {
    Serial.printf( "Unable to initialize the network; hardware status is %d\n",
                   Ethernet.hardwareStatus());
    HANG;
  }

  Serial.print( "Mac address: " );
  for( int ii = 0; ii < 6; ii++ )
  {
    if( macAddress[ii] < 16 ) { Serial.print( '0' ); }
    Serial.print( macAddress[ii], HEX );
    if( ii < 5 ) { Serial.print( ':' ); }
  }
  Serial.println();
  Serial.print( "DNS IP:      " ); Serial.println( Ethernet.dnsServerIP());
  Serial.print( "Local IP:    " ); Serial.println( Ethernet.localIP());
  Serial.print( "Gateway IP:  " ); Serial.println( Ethernet.gatewayIP());
  Serial.print( "Subnet mask: " ); Serial.println( Ethernet.subnetMask());

  if( !player.begin())
  {
    Serial.println( "Unable to initialize the MusicMaker" );
    HANG;
  }
  Serial.println( "Initialized the MusicMaker" );
  player.setVolume( 40, 40 );
  player.sineTest( 0x44, 1000 ); // 1KHz tone for one second.

  contentLength = beginRequest();
  Serial.printf( "HTTP content length: %d\n", contentLength );
}

void loop()
{
  if( player.readyForData())
  {
    if( client.available() > 0 )
    {
      uint8_t bytesRead = client.read( mp3Buf, VS1053_DATABUFFERLEN );
      if( bytesRead > 0 )
      {
        player.playData( mp3Buf, bytesRead );
        contentLength -= bytesRead;
        if( contentLength <= 0 )
        {
          Serial.println( "That should be all of our sound" );
        }
      }
    }
  }
}

uint32_t beginRequest()
{
  if( !client.connect( host, port ))
  {
    Serial.print( "Unable to connect to " );
    Serial.print( host ); Serial.print( ':' ); Serial.println( port );
    HANG;
  }

  Serial.print( "GET " ); Serial.print( path ); Serial.print( " HTTP/1.1\r\n" );
  Serial.print( "Host: " ); Serial.print( host ); Serial.print( "\r\n" );
  Serial.print( "Connection: close\r\n\r\n" );

  client.print( "GET " ); client.print( path ); client.print( " HTTP/1.1\r\n" );
  client.print( "Host: " ); client.print( host ); client.print( "\r\n" );
  client.print( "Connection: close\r\n\r\n" );

  char http[] = "HTTP/";
  client.find( http );                  // Skip over the HTTP/ part of the header.
  client.parseFloat( SKIP_WHITESPACE ); // Skip over the HTTP version number.

  int httpStatus = client.parseInt( SKIP_WHITESPACE );
  if( httpStatus < 200 || httpStatus > 299 )
  {
    Serial.printf( "GET request failed; HTTP status is %d\n", httpStatus );
    client.stop();
    HANG;
  }

  char lengthHeader[] = "Content-Length:";
  client.find( lengthHeader );
  int contentLength = client.parseInt();

    char endOfHeaders[] = "\r\n\r\n";
  if( !client.find( endOfHeaders ))
  {
    Serial.println( "Invalid HTTP response (missing trailing line endings)" );
    client.stop();
    HANG;
  }
  return contentLength;
}

void readMacAddress( byte* addr )
{
  Wire.beginTransmission( MAC_EEPROM_I2C_ADDRESS );
  Wire.write( MAC_EEPROM_REGISTER );
  int failed = Wire.endTransmission();
  if( failed )
  {
    Serial.printf( "Unable to retrieve MAC address; endTransmission returned %d\n", failed );
    HANG;
  }

  byte* b = addr;
  int bytesRead = Wire.requestFrom( MAC_EEPROM_I2C_ADDRESS, 6 );
  if( bytesRead < 6 )
  {
    Serial.printf( "Unable to retrieve MAC address; fewer than six bytes\n" );
    HANG;
  }

  while( Wire.available())
  {
    *b++ = Wire.read();
  }
}
2
  • is a SD card inserted? if yes, then remove it or set the CS pin HIGH at the beginning of setup(). set the CS pin of the player HIGH before Ethernet.begin()
    – Juraj
    Commented Apr 12, 2022 at 18:04
  • Set both the SD card CS and the player CS to outputs and set them high prior to Ethernet.init() and Ethernet.begin(). If both Ethernet and player are initialized, neither works. player's sineTest() method doesn't do anything and EthernetClient's connect() method returns zero. They both use SPI. Could there be some sort of conflict there? Commented Apr 12, 2022 at 21:54

1 Answer 1

0

Turned out to be a hardware problem.

The PoE FeatherWing's default CS pin conflicts with the MusicMaker's DCS pin. The PoE CS pin can be changed by cutting a trace on the back of the board and bodging a wire from a pad to whatever pin you want to use instead. I had done that.

Turns out though, that I hadn't cut it completely. This was causing the Ethernet library to pull the MusicMaker DCS low every time it pulled the Ethernet CS low.

I finally figured it out when I hooked up a logic analyzer to all of the CS pins and the SPI pins. It was very clear that MusicMaker DCS was going low with Ethernet CS.

Yay Logic Analyzer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.