USE UPS NEXT DAY AIR FOR ANY USA ORDER BEFORE 11AM ET *TODAY* 12/19/2014 TO GET YOUR PACKAGE IN TIME FOR XMAS - PLEASE SEE OUR SHIPPING DEADLINE NOTICE FOR MORE DETAILS!

Waveshield + ht1632c = Fail
Moderators: adafruit_support_bill, adafruit

Waveshield + ht1632c = Fail

by cbonsig on Tue Mar 12, 2013 2:46 am

Hello! I've been working on a project that integrates an Arduino UNO with a touchscreen, Sure Electronics 16x32 bicolor LED, Chronodot, and Waveshield. The good news: I have everything working! The bad news: Not at the same time! The hardware is all integrated and functioning. I can load up a Waveshield demo sketch, and it works perfectly. I can load up my code for the touchscreen clock, and it works perfectly. But when I try to add the Waveshield libraries into the clock sketch, nothing works anymore.

I can't use serial communications to diagnose the problem because I have to use RX/TX pins 1 and 2 to communicate with the ht1632c LED. I wonder if that's part of the problem -- I tried commenting out <WaveUtil.h> and any of the waveshield functions that were trying to use the serial port, but that didn't help. The binary sketch size for the combined code is about 24k (of 32k max). Maybe its a memory problem? SRAM?

I'm stuck. Any suggestions?

The code is here if you want to check it out. The minimum additional code that I added for the waveshield is below.
https://github.com/cbonsig/openclock

Code: Select all | TOGGLE FULL SIZE
...
#include <WaveHC.h>
//#include <WaveUtil.h>
SdReader card;    // This object holds the information for the card
FatVolume vol;    // This holds the information for the partition on the card
FatReader root;   // This holds the information for the volumes root directory
FatReader file;   // This object represent the WAV file for a pi digit or period
WaveHC wave;      // This is the only wave (audio) object, since we will only play one at a time
...
void setup(){
...
  playcomplete("CLK_TOWR.WAV");
}

/////////////////////////////////// HELPERS for WaveShield

char filename[13];
void speaknum(char c) {
  uint8_t i=0;

  // copy flash string for 'period' to filename
  strcpy_P(filename, PSTR("P.WAV"));

  if ('0' <= c && c <= '9') {
    // digit - change 'P' to digit
    filename[0] = c;
    i = 1;
  }
  else if (c != '.') {
    // error if not period
    return;
  }
  playcomplete(filename);
}
/*
 * print error message and halt
 */
//void error_P(const char *str) {
//  PgmPrint("Error: ");
//  SerialPrint_P(str);
//  sdErrorCheck();
//  while(1);
//}
/*
 * print error message and halt if SD I/O error
 */
//void sdErrorCheck(void) {
//  if (!card.errorCode()) return;
//  PgmPrint("\r\nSD I/O error: ");
//  Serial.print(card.errorCode(), HEX);
//  PgmPrint(", ");
//  Serial.println(card.errorData(), HEX);
//  while(1);
// }
/*
 * Play a file and wait for it to complete
 */
void playcomplete(char *name) {
  playfile(name);
  while (wave.isplaying);

  // see if an error occurred while playing
//  sdErrorCheck();
}
/*
 * Open and start playing a WAV file
 */
void playfile(char *name) {
  if (wave.isplaying) {// already playing something, so stop it!
    wave.stop(); // stop it
  }
//  if (!file.open(root, name)) {
//    PgmPrint("Couldn't open file ");
//    Serial.print(name);
//    return;
//  }
//  if (!wave.create(file)) {
//    PgmPrintln("Not a valid WAV");
//    return;
//  }
  // ok time to play!
  wave.play();
}
cbonsig
 
Posts: 13
Joined: Sat Jan 28, 2012 11:20 am

Re: Waveshield + ht1632c = Fail

by adafruit_support_bill on Tue Mar 12, 2013 6:59 am

I can't use serial communications to diagnose the problem because I have to use RX/TX pins 1 and 2 to communicate with the ht1632c LED.

Hardware serial is on pins 0 and 1. Those are the pins used to communicate w/ the serial monitor.

Also, you have commented out the line where it actually opens the file in "playfile()":
Code: Select all | TOGGLE FULL SIZE
/*
* Open and start playing a WAV file
*/
void playfile(char *name) {
  if (wave.isplaying) {// already playing something, so stop it!
    wave.stop(); // stop it
  }
//  if (!file.open(root, name)) {  // <<--------------------this is where the file is opened
//    PgmPrint("Couldn't open file ");
//    Serial.print(name);
//    return;
//  }
//  if (!wave.create(file)) {
//    PgmPrintln("Not a valid WAV");
//    return;
//  }
  // ok time to play!
  wave.play();
}
User avatar
adafruit_support_bill
 
Posts: 32619
Joined: Sat Feb 07, 2009 10:11 am

Re: Waveshield + ht1632c = Fail

by cbonsig on Wed Mar 13, 2013 1:45 am

Some more diagnostics. I took a step backwards, and created a simple sketch that combines WaveHC + ht1632c libraries. As long as I eliminate Serial.begin() any related attempts at serial communication, I can get the Waveshield and LED screen to work correctly at the same time. Yea! This means that there are no deal-breaker hardware conflicts here (apart from the hardware serial conflict on pins 0+1, which I can live with).

Here's the trouble. When I implement my serial-free Waveshield code from the above simple sketch in my more complicated touchscreen clock sketch, things start to get weird again. I can't get it to play any .WAV sounds, in setup{} or loop{}. If I do have a playcomplete("file.wav") anywhere in the code, the display doesn't work. And strangely, if I comment out any of "play" lines in setup{} or loop{} (leaving the headers, objects, and helpers in place) the time digits display fine on the clock, but the AM/PM characters are corrupted, and the touchscreen functions don't work. There is no logical explanation for this, as the Waveshield code has nothing at all to do with character variables, or any of the touchscreen logic.

I'm left to suspect that the problem here is somehow memory related, and that perhaps I've exhausted SRAM, or some variable are being overwritten. Any other suggestions? I've been using the SpeakPiHC sketch as a template. Is there another alternative Waveshield example with the smallest possible memory/resource footprint?
cbonsig
 
Posts: 13
Joined: Sat Jan 28, 2012 11:20 am

Re: Waveshield + ht1632c = Fail

by adafruit_support_bill on Wed Mar 13, 2013 6:28 am

Between file buffers and screen buffers, you are consuming a big chunk of the 2K of SRAM on the Arduino. You may be able to optimize enough to get it working. There are some good tips here: http://itp.nyu.edu/~gpv206/2008/04/maki ... o_mem.html

The other option would be to move to a Mega with 4x the SRAM.
User avatar
adafruit_support_bill
 
Posts: 32619
Joined: Sat Feb 07, 2009 10:11 am

Re: Waveshield + ht1632c = Fail

by cbonsig on Wed Mar 13, 2013 1:46 pm

Thanks. I will try to get the memory usage down. I was able to figure out how to use avr-size to measure memory usage for the compiled code. For the UNO (atmega328), the static RAM allocation situation is this:

[*] Openclock (touchscreen clock without Waveshield libraries) uses 19%
[*] PiSpeakHC (simple waveshield demo) uses 66%
[*] Openclock + Waveshield libraries uses 85%

So even though I'm not over 100% with the combined sketch, I know this doesn't account for dynamic memory allocation that occurs during runtime. I might try to use http://playground.arduino.cc/Code/AvailableMemory to investigate further, but that's a bit tricky because I can't use serial communication. I should be able to display available memory on my ht1632c LED. Here's what's still puzzling to me, though:

About 600 bytes of SRAM are used to buffer the audio and keep track of file data, so RAM-heavy projects may not work well (http://www.ladyada.net/make/waveshield/)


I understand that the Waveshield library should need at least 600 bytes, but the sample code is using over 2x that, 1363 bytes. Is it possible to reduce the waveshield memory footprint from 1363 down to something closer to 600? I really only need to play a single pre-determined audio file, if that helps.


Code: Select all | TOGGLE FULL SIZE
Craigs-MacBook-Pro:build5738900879726911325.tmp cbonsignore$ pwd
/var/folders/jv/vtwn5y8s41vcvngw6n4j55xw0000gn/T/build5738900879726911325.tmp

Craigs-MacBook-Pro:build5738900879726911325.tmp cbonsignore$ /Applications/Arduino.app/Contents/Resources/Java/hardware/tools/avr/bin/avr-size -C --mcu=atmega328p PiSpeakHC.cpp.elf
AVR Memory Usage
----------------
Device: atmega328p

Program:    9846 bytes (30.0% Full)
(.text + .data + .bootloader)

Data:       1363 bytes (66.6% Full)
(.data + .bss + .noinit)

cbonsig
 
Posts: 13
Joined: Sat Jan 28, 2012 11:20 am

Re: Waveshield + ht1632c = Fail

by adafruit_support_bill on Wed Mar 13, 2013 2:13 pm

One common memory hog is literal strings. If you use a string in a printf statement it gets copied into SRAM before execution. One easy way to save memory is to use the "F()" macro added in Arduino 1.0.

Instead of:
Code: Select all | TOGGLE FULL SIZE
printf("Hello World");

You can use:
Code: Select all | TOGGLE FULL SIZE
printf(F("Hello World"));
 

and the string will be printed from flash.
User avatar
adafruit_support_bill
 
Posts: 32619
Joined: Sat Feb 07, 2009 10:11 am

Re: Waveshield + ht1632c = Fail

by cbonsig on Fri Mar 15, 2013 1:33 am

I've done everything I can imagine to get the RAM demands of my code down, but it isn't enough. Is there any way reduce the RAM requirements of WaveHC, in exchange for more limited flexibility or functionality? I've looked through the library code, but its just way beyond my comprehension. I can't even figure out where in the code the major memory culprits are.

I did order a MEGA, just in case, but I really hope there's some way to make it work on the UNO. Its sooooo close!!

(FYI, there are some more details on http://clock.bonsignore.com)
cbonsig
 
Posts: 13
Joined: Sat Jan 28, 2012 11:20 am

Re: Waveshield + ht1632c = Fail

by adafruit_support_bill on Fri Mar 15, 2013 6:56 am

I really hope there's some way to make it work on the UNO. Its sooooo close!!

Any idea how close?

I see some opportunities for optimizing your code. For example:
Code: Select all | TOGGLE FULL SIZE
  // map pixel location to screen region
  if      (px >=0  && px <=8 )  horizontalRegion = 1;        // x pixel 0-8   = 1st digit of hour
  else if (px >=9  && px <=17)  horizontalRegion = 2;        // x pixel 9-17  = 2nd digit of hour
  else if (px >=18 && px <=25)  horizontalRegion = 3;        // x pixel 18-25 = 1st digit of minute
  else if (px >=26 && px <=33)  horizontalRegion = 4;        // x pixel 26-33 = 2nd digit of minute
  else                          horizontalRegion = 0;

  if      (py >=0  && py <=5 )  verticalRegion = 1;          // y pixel 0-5   = top of time digits
  else if (py >=6  && py <=10)  verticalRegion = 2;          // y pixel 6-10  = bottom of time digits
  else if (py >=11 && py <=16)  verticalRegion = 3;          // y pixel 11-16 = message / ampm area
  else                          verticalRegion = 0;

could be reduced to:
Code: Select all | TOGGLE FULL SIZE
horizontalRegion = px/8;
if (horizontalRegion < 0 || horizontalRegion > 4)
{
    horizontalRegion = 0;
}
verticalRegion  = py/5;
if (verticalRegion  < 0 || verticalRegion  > 3)
{
    verticalRegion  = 0;
}




Nice looking project by the way :D
User avatar
adafruit_support_bill
 
Posts: 32619
Joined: Sat Feb 07, 2009 10:11 am

Re: Waveshield + ht1632c = Fail

by cbonsig on Sat Mar 16, 2013 2:27 am

Thanks! I can report some progress... I was able to squeeze another 32 bytes out of SRAM. Not enough. But then I found this thread where someone else was having a similar problem with a Waveshield and 32x16 LED display:

http://arduino.cc/forum/index.php?PHPSESSID=fc1e932fc7667b8c42ee0dc262bc883a&topic=132866.15

They solved the problem by upgrading the UNO to a MEGA. However, someone pointed out that <WaveHC.h> sets the buffer size at 256 bytes for the ATmega168 and 512 bytes for ATmega328 and all other Arduinos. So I added an override
Code: Select all | TOGGLE FULL SIZE
#define PLAYBUFFLEN 256UL
. This is just the hack I was looking for -- it significantly reduces the memory footprint for WaveHC. Now:

Good news: The waveshield library, utility library, objects, and helper functions all fit neatly into memory with about 570 bytes to spare, as reported by freeRam(). And the display, touchscreen, and menu functions work perfectly.

Bad news: Audio still doesn't play as part of this combined sketch. Even the shortest little .WAV file fails to play, whether called from setup{} or loop{}.

The example sketches still work fine, so the change that I made to the library is OK. My code is updated at https://github.com/cbonsig/openclock/tree/master/openclock

I'm not sure what to try next. If all else fails, I now know that everything should work fine with the MEGA / ATmega2560.
cbonsig
 
Posts: 13
Joined: Sat Jan 28, 2012 11:20 am

Re: Waveshield + ht1632c = Fail

by adafruit_support_bill on Sat Mar 16, 2013 5:36 am

In your setup, you are not calling cardInit().
User avatar
adafruit_support_bill
 
Posts: 32619
Joined: Sat Feb 07, 2009 10:11 am

Re: Waveshield + ht1632c = Fail

by cbonsig on Sat Mar 16, 2013 7:21 pm

THAT'S IT! Success! I was missing all of the setup{} stuff. An easy fix. Many thanks!!

fully functioning code on github. https://github.com/cbonsig/openclock
cbonsig
 
Posts: 13
Joined: Sat Jan 28, 2012 11:20 am