HELP WITH CC3000 AND VS1053 MP3 PLAYER

General project help for Adafruit customers

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
mpenna
 
Posts: 9
Joined: Fri Feb 28, 2014 10:34 am

HELP WITH CC3000 AND VS1053 MP3 PLAYER

Post by mpenna »

Hi,

I'm working on a project which aims to download MP3 files from an Internet server, have them be cached locally on a Micro-SD card and then have them played back upon user request/interaction. For prototyping purposes, I got an Arduino Micro, a CC3000 WiFi module (breakout) and a VS1053 player module (breakout) along with some additional accessories (Powerboost, audio amplifier, speaker, etc.). While still at the very beginning of the whole process, I have already been able to successfully run right off the bat a couple of the CC3000 example sketches that come with the library. That was pretty cool, but I'm not sure if the road ahead will continue to be that smooth, since I'm having a bit of trouble trying to find some or any references on how to download an audio file via HTTP from a web server with the CC3000. I may be wrong, but considering the memory constraints imposed by the Arduino this would probably need to be done through some sort of streaming/chunking process, right? I hope this is at all possible -- the lack of references are kind of putting me down. Any ideas and help would be greatly appreciated.

User avatar
adafruit_support_mike
 
Posts: 67454
Joined: Thu Feb 11, 2010 2:51 pm

Re: HELP WITH CC3000 AND VS1053 MP3 PLAYER

Post by adafruit_support_mike »

The basic process is the same for any kind of file: read a buffer's worth of data from the CC3000 and write it to the SD card.

When you request a file from an HTTP server, the response starts with a list of headers that tell you things about the file like its type and its size. Then there's a blank line, and the content follows that.

Find and store the value of the Content-length header, then keep track of the number of bytes you've read and stored. When you've read the correct amount, the transmission should be done.

mpenna
 
Posts: 9
Joined: Fri Feb 28, 2014 10:34 am

Re: HELP WITH CC3000 AND VS1053 MP3 PLAYER

Post by mpenna »

Thanks, I'll try to look into that. If perhaps you could point me to some examples, it'd be great. And talking about examples, I was wondering if one could use with the CC3000 module the examples that come with Arduino's (native?) WiFi library (available under the "File > Examples" menu). I guess not, right?

Just another question or two...

I'm kind of a noob when it comes to the Arduino ecosystem, but (correct me if I am wrong) both the CC3000 and the VS1053 use the SPI bus to communicate with the processor, right? Does this mean that I'm heading towards some trouble, considering that this chunking process demands communicating with both modules at the same time? What should I be looking for in order to get this process running without getting into major problems?

And what about accessing the Micro-SD card that's on the VS1053... will I be able to use it as the storage medium for the downloaded file or is it only available (internally?) to the VS1053 module? Not sure if this makes any sense, but again my lack of experience may be the culprit here.

Thanks again.

User avatar
adafruit_support_mike
 
Posts: 67454
Joined: Thu Feb 11, 2010 2:51 pm

Re: HELP WITH CC3000 AND VS1053 MP3 PLAYER

Post by adafruit_support_mike »

The buffered read/write would look something like this:

Code: Select all

  unsigned long lastRead = millis();
  char buffer[ 256 ];
  int i = 0;
  
  while (www.connected() && (millis() - lastRead < IDLE_TIMEOUT_MS)) {
    while (www.available()) {
      buffer[ i++ ] = www.read();
      lastRead = millis();
      
      if ( i >= 255 ) {
        buffer[ 255 ] = 0;
        i = 0;
        myFile.print( buffer );
      }
    }
  }
  buffer[ i ] = 0;
  myFile.print( buffer );
  myFile.flush();
  myFile.close();
  www.close();
WRT the SPI devices, yes, the CC3000, the VS1053, and the SD card all use the SPI bus. The SD library also has some limits on file access, so you won't be able to load/write and read/play at the same time.

The SD card on the VS1053 is more or less independent of the VS1053 itself. We build all our breakouts that way so you don't have to use the card if you don't want to, and can use any card on any breakout for any purpose. Again, there are some limits in the library that restrict you to a single card per Arduino, but that doesn't cause too many problems.

mpenna
 
Posts: 9
Joined: Fri Feb 28, 2014 10:34 am

Re: HELP WITH CC3000 AND VS1053 MP3 PLAYER

Post by mpenna »

Thanks... your pointers are helping me a great deal! I ended up getting an Arduino Mega 2560 because I couldn't cram my sketch into the limited memory of the Micro. I haven't even developed it fully, but just stitching together two examples (one for the CC3000 lib, one for the VS1053 lib) that I'm using as a jumping-off pont for my own sketch already surpassed the available memory on the Micro. I got the Mega today and I've already done some progress, but now it seems that I've stumbled upon some problem I believe related to not being able to use both modules at the same time -- not sure how to overcome this though. Could you please take a look at the fragment of code below to see if there's anything that I should be doing differently?

Whenever I run this sketch, the program apparently halts once it reaches past the point where the previously existing file is removed from the SD card. If I comment out the downloading loop, the file gets to be created without any problems, albeit with 0 bytes (obviously).

Code: Select all


Serial.println(F("-------------------------------------"));
Serial.println(F("downloading file... "));

uint16_t i = 0;
uint32_t lastRead = millis();
uint16_t content_length = 0;
boolean parsingHeader = true;
boolean statusOk = false;
char buffer[BUFFER_SIZE];
char c;

if (SD.exists(FILE_NAME))
{
	Serial.println(F("removing existing ogg file..."));
	SD.remove(FILE_NAME);
}

File dd = SD.open(FILE_NAME, FILE_WRITE);

while (www.connected() && (millis() - lastRead < IDLE_TIMEOUT_MS))
{
	while (www.available())
	{
		if (parsingHeader)
		{
			Serial.println(F("parsing header"));

			if (www.find((char*)"HTTP/1.1 "))
			{
				char statusCode[] = "000";
				www.readBytes(statusCode, 3);
				statusOk = (strcmp(statusCode, "200") == 0);
				Serial.print(F("Status Code: "));
				Serial.println(statusCode);
			}

			if (www.find((char*)"Content-Length: "))
			{
				while (isdigit(c = www.read()))
				{
					content_length = (content_length * 10) + (c - '0');
				}
				Serial.print(F("Content-Length: "));
				Serial.println(content_length);
			}

			www.find((char*)"\n\r\n");

			parsingHeader = false;
		}
		else
		{
			buffer[i++] = www.read();
			if (i >= BUFFER_SIZE - 1)
			{
				buffer[BUFFER_SIZE - 1] = 0;
				i = 0;
				dd.write(buffer);
			}
		}
		lastRead = millis();
	}
}

buffer[i] = 0;
dd.write(buffer);
dd.close();

www.close();

Serial.println(F("request complete"));
Serial.println(F("-------------------------------------"));


User avatar
adafruit_support_mike
 
Posts: 67454
Joined: Thu Feb 11, 2010 2:51 pm

Re: HELP WITH CC3000 AND VS1053 MP3 PLAYER

Post by adafruit_support_mike »

You're calling a function named 'find()' that isn't defined anywhere in the CC3000 library:

Code: Select all

         if (www.find((char*)"HTTP/1.1 "))
Where does that come from?

mpenna
 
Posts: 9
Joined: Fri Feb 28, 2014 10:34 am

Re: HELP WITH CC3000 AND VS1053 MP3 PLAYER

Post by mpenna »

It's a method available under the Stream object/class, which I believe the Adafruit_CC3000_Client class eventually extends, right? It reads into the data stream, looking for tokens of data that I then use for parsing the response's header. That part is working OK. The issue, as I believe, lies further down, when I try to interleave both downloading and saving the chunks of data. If I comment out any SD functionality from that part of the code, the download apparently runs OK. I don't know, it could well be something else, but, again, the parsing of the response header is working without any apparent problems.

User avatar
adafruit_support_mike
 
Posts: 67454
Joined: Thu Feb 11, 2010 2:51 pm

Re: HELP WITH CC3000 AND VS1053 MP3 PLAYER

Post by adafruit_support_mike »

Oh, that's right.. I'd forgotten the class hierarchy.

Try commenting out the line that writes the file while you're downloading information, but writes a fixed string to the file after the download is done.

mpenna
 
Posts: 9
Joined: Fri Feb 28, 2014 10:34 am

Re: HELP WITH CC3000 AND VS1053 MP3 PLAYER

Post by mpenna »

I have tried as you suggested. I commented out the line that writes the downloaded chunks of data to the file and once the download has finished, I then write a test string to the file before closing it. I'm leaning more and more toward the feeling that something is definitely not working properly when putting these two functionalities together. This, because the sketch now works sometimes while other times it doesn't -- more occurrences of the latter, actually. Sometimes it blocks when trying to delete the already existing file, other times it blocks when trying to create the file, sometimes the download runs all the way through but the code then blocks immediately after, when I try to play a test MP3 file present on disk. It looks like there's no deterministic pattern to be found in the occurrences of these errors.

I'm no expert in Arduino, but from what I've been able to assess (and understand) so far is that we're probably dealing with some kind of SPI awkwardness here. My limited knowledge in such matters tends to conclude that there's something more that needs to be done to properly control and tame the SPI communication between these modules. As I mentioned previously, they all work individually, but once we stitch them together, boom!

I'm pasting the whole sketch now in hope that you can find something wrong with it.

Code: Select all

#include <Adafruit_CC3000.h>
#include <Adafruit_VS1053.h>
#include <SPI.h>
#include <SD.h>
#include "utility\debug.h"


/*
Use hardware pins for SPI communication:
- UNO:  10 (SS), 11 (MOSI), 12 (MISO), 13 (SCK)
- MEGA: 53 (SS), 51 (MOSI), 50 (MISO), 52 (SCK)
*/


#pragma region VS1053 CONSTANTS

// must be an interrupt pin
#define VS1053_DREQ 2
// can be any pins
#define VS1053_RST 5
#define VS1053_CS 53
#define VS1053_SDCS 6
#define VS1053_XDCS 8

#pragma endregion


#pragma region CC3000 CONSTANTS

// must be an interrupt pin
#define CC3000_IRQ 3
// can be any pins
#define CC3000_VBEN 7
#define CC3000_CS 31

#pragma endregion


#pragma region NETWORKING CONSTANTS

// WLAN connection information
// SSID cannot be longer than 32 characters
// security can be: WLAN_SEC_UNSEC, WLAN_SEC_WEP, WLAN_SEC_WPA, WLAN_SEC_WPA2
#define WLAN_SSID "........."        
#define WLAN_PASS "........."
#define WLAN_SECURITY WLAN_SEC_WPA2

// request info
#define WEBSITE "bebox.com.br"
#define WEBPAGE "/mp3/AlGreenLove.ogg"

// time to wait (ms) if no data is received before closing the connection  
#define IDLE_TIMEOUT_MS 3000

// download buffer size
#define BUFFER_SIZE 32

#define FILE_NAME "agl.ogg"

#pragma endregion


#pragma region GLOBAL VARS

// create VS1053 object
Adafruit_VS1053_FilePlayer musicPlayer = 
	Adafruit_VS1053_FilePlayer(
		VS1053_RST,
		VS1053_CS,
		VS1053_XDCS,
		VS1053_DREQ,
		VS1053_SDCS);

// create CC3000 object
Adafruit_CC3000 cc3000 = 
	Adafruit_CC3000(
		CC3000_CS,
		CC3000_IRQ,
		CC3000_VBEN,
		SPI_CLOCK_DIVIDER);

// server ip
uint32_t ip;

#pragma endregion


void setup(void)
{
	Serial.begin(115200);

	Serial.println(F("CC3000 + VS1053"));

	Serial.print(F("\nFree RAM: "));
	Serial.println(getFreeRam(), DEC);

	// ------------------------------------------

	// initialize the CC3000 module
	Serial.println(F("\nInitializing WiFi..."));
	if (!cc3000.begin())
	{
		Serial.println(F("... couldn't initialize CC3000"));
		while (1);
	}

	// connect to access point
	Serial.print(F("\nConnecting to: "));
	Serial.println(WLAN_SSID);
	if (!cc3000.connectToAP(WLAN_SSID, WLAN_PASS, WLAN_SECURITY))
	{
		Serial.println(F("... failed connecting to access point"));
		while (1);
	}

	// wait for DHCP to complete
	Serial.println(F("\nRequesting DHCP"));
	while (!cc3000.checkDHCP())
	{
		// ToDo: Insert a DHCP timeout!
		delay(100);
	}

	ip = 0;

	// try looking up the web site's IP address
	Serial.print(F("\n"));
	Serial.print(WEBSITE);
	Serial.print(F(" -> "));
	while (ip == 0)
	{
		if (!cc3000.getHostByName(WEBSITE, &ip))
		{
			Serial.print(F("\n... couldn't resolve hostname"));
		}
		delay(500);
	}

	cc3000.printIPdotsRev(ip);

	// ------------------------------------------

	// initialize the VS1053 module
	Serial.println(F("\nInitializing VS1053..."));
	if (!musicPlayer.begin()) {
		Serial.println(F("... couldn't find VS1053"));
		while (1);
	}

	// initialize the SD card
	Serial.println(F("\nInitializing SD..."));
	if (!SD.begin(VS1053_SDCS))
	{
		Serial.println(F("... couldn't find SD"));
		while (1);
	}

	// set volume for left, right channels (lower numbers == louder volume)
	musicPlayer.setVolume(10, 10);

	// if DREQ is on an interrupt pin we can do background audio playing
	musicPlayer.useInterrupt(VS1053_FILEPLAYER_PIN_INT);

	// ------------------------------------------

	// try connecting to the website
	// HTTP/1.1 protocol is used to keep the server from closing the connection before all data is read
	Adafruit_CC3000_Client www = cc3000.connectTCP(ip, 80);
	if (www.connected())
	{
		// send request
		www.fastrprint(F("GET ")); www.fastrprint(WEBPAGE); www.fastrprint(F(" HTTP/1.1\r\n"));
		www.fastrprint(F("Host: ")); www.fastrprint(WEBSITE); www.fastrprint(F("\r\n"));
		www.fastrprint(F("\r\n"));
		www.println();
	}
	else
	{
		Serial.println(F("Connection failed"));
		return;
	}

#pragma region Downloading

	Serial.println(F("\nDownloading file... "));

	uint16_t i = 0;
	uint32_t lastRead = millis();
	uint16_t contentLength = 0;
	boolean parsingHeader = true;
	boolean statusOk = false;
	char buffer[BUFFER_SIZE];
	char c;

	if (SD.exists(FILE_NAME))
	{
		Serial.println(F("\nRemoving existing file..."));
		SD.remove(FILE_NAME);
	}

	File dd = SD.open(FILE_NAME, FILE_WRITE);

	Serial.println(F("\nFile created..."));

	while (www.connected() && (millis() - lastRead < IDLE_TIMEOUT_MS))
	{
		while (www.available())
		{
			if (parsingHeader)
			{
				Serial.println(F("\nParsing header"));

				if (www.find((char*)"HTTP/1.1 "))
				{
					char statusCode[] = "000";
					www.readBytes(statusCode, 3);
					statusOk = (strcmp(statusCode, "200") == 0);
					Serial.print(F("\nStatus Code: "));
					Serial.println(statusCode);
				}

				if (www.find((char*)"Content-Length: "))
				{
					while (isdigit(c = www.read()))
					{
						contentLength = (contentLength * 10) + (c - '0');
					}
					Serial.print(F("\nContent-Length: "));
					Serial.println(contentLength);
				}

				www.find((char*)"\n\r\n");

				parsingHeader = false;
			}
			else
			{
				buffer[i++] = www.read();
				if (i >= BUFFER_SIZE - 1)
				{
					buffer[BUFFER_SIZE - 1] = 0;
					Serial.println(buffer);
					//dd.write(buffer);
					i = 0;
				}
			}
			lastRead = millis();
		}
	}

	buffer[i] = 0;
	Serial.println(buffer);
	//dd.write(buffer);
	dd.write("testing");

	dd.close();

	www.close();

	Serial.println(F("\nRequest complete"));

#pragma endregion

	// close the CC3000 connection
	Serial.println(F("\n\nDisconnecting"));
	cc3000.disconnect();

	// ------------------------------------------

	//// play downloaded file (background)
	//if (SD.exists(FILE_NAME))
	//{
	//	Serial.println(F("\nPlaying downloaded file..."));
	//	musicPlayer.startPlayingFile(FILE_NAME);
	//}

	// JUST A TEST ------------------------------------------

	// play test file (blocking)
	if (SD.exists("track001.mp3"))
	{
		Serial.println(F("\nPlaying track001.mp3..."));
		musicPlayer.playFullFile("track001.mp3");
	}
}


void loop(void)
{
	// file is playing in the background
	if (musicPlayer.stopped()) {
		Serial.println("done playing music");
		while (1);
	}

	if (Serial.available()) {
		char c = Serial.read();

		// if we get an 's' on the serial console, stop
		if (c == 's') {
			musicPlayer.stopPlaying();
		}

		// if we get an 'p' on the serial console, pause/unpause
		if (c == 'p') {
			if (!musicPlayer.paused()) {
				Serial.println("paused");
				musicPlayer.pausePlaying(true);
			}
			else {
				Serial.println("resumed");
				musicPlayer.pausePlaying(false);
			}
		}
	}

	delay(100);
}

User avatar
adafruit_support_mike
 
Posts: 67454
Joined: Thu Feb 11, 2010 2:51 pm

Re: HELP WITH CC3000 AND VS1053 MP3 PLAYER

Post by adafruit_support_mike »

It might also be a memory problem.

Take a look at this tutorial page for information about how to measure memory usage while a program is running. If the numbers start to get low before the code hangs, that's a sign of memory trouble:

https://learn.adafruit.com/memories-of- ... ree-memory

mpenna
 
Posts: 9
Joined: Fri Feb 28, 2014 10:34 am

Re: HELP WITH CC3000 AND VS1053 MP3 PLAYER

Post by mpenna »

I'm using a Mega 2560 now, so there's plenty of space left for the sketch (it currentlly uses only 14% of Flash memory) while printing the result of a "getFreeRam()" (debug.h) shows that more than 5KB is available at program start.

mpenna
 
Posts: 9
Joined: Fri Feb 28, 2014 10:34 am

Re: HELP WITH CC3000 AND VS1053 MP3 PLAYER

Post by mpenna »

Any other ideas? What about my concerns towards SPI? Any validity to that? Furthermore, I'm amazed that no one else has picked up on this conversation. Could it be that I'm the only one trying to do something with these two modules in tandem?

User avatar
adafruit_support_mike
 
Posts: 67454
Joined: Thu Feb 11, 2010 2:51 pm

Re: HELP WITH CC3000 AND VS1053 MP3 PLAYER

Post by adafruit_support_mike »

Hmm.. looking at the libraries, the VS1053 has the option to use an interrupt pin to handle the timing on refilling the buffer.

Using that option will almost certainly cause the CC3000 to crash. The library for that also uses interrupts and the timing is critical.

mpenna
 
Posts: 9
Joined: Fri Feb 28, 2014 10:34 am

Re: HELP WITH CC3000 AND VS1053 MP3 PLAYER

Post by mpenna »

I'm not exactly an expert on this, but according to the tutorials and all, I'm pretty sure I'm using dedicated (and separate) interrupt pins for both the CC3000 and the VS1053. Couldn't it be something related to the "chip select" logic? As far as I understand all this, isn't that what signals and controls the communication between microcontroller and modules on the (same) SPI bus? Maybe the libraries don't handle this automatically? Just throwing some ideas around.

Anyway... thanks for hanging in with me on this one...

User avatar
adafruit_support_mike
 
Posts: 67454
Joined: Thu Feb 11, 2010 2:51 pm

Re: HELP WITH CC3000 AND VS1053 MP3 PLAYER

Post by adafruit_support_mike »

I think we may be looking at the same issue from different directions.

Interrupts, even on separate pins, make the flow of execution very hard to predict. All interrupts take priority over whatever code is running at the time, so if the Arduino is busy talking to the CC3000 when a VS1053 interrupt arrives, the Arduino will immediately try to open a connection to the SD card and read more data into the VS1053's play buffer.

The VS1053 library doesn't know anything about the CC3000, and specifically doesn't know anything about the CC3000's CS pin. It assumes the SD card is the only SPI device connected to the Arduino, or that any other SPI device will be shut off while the VS1053 is trying to play.

It's highly possible that an interrupt could try to pull the SD card's CS pin LOW while the CC3000's CS pin is LOW, and the result would be a train wreck.

Locked
Please be positive and constructive with your questions and comments.

Return to “General Project help”