Curious Phenomenon with the Wave Shield

Adafruit Ethernet, Motor, Proto, Wave, Datalogger, GPS Shields - etc!

Moderators: adafruit_support_bill, adafruit

Curious Phenomenon with the Wave Shield

Postby pburgess » Fri Oct 31, 2008 1:03 am

Something I've encountered with the Wave Shield, might have implications for certain other folks experiencing crashes and whatnot:

The scenario: everything works great so long as programs do nothing else while playing; as with the 'pispeak' sketch, they sit in a tight loop while each sound plays. However, attempts to make sounds "interruptible" in response to external triggers (button presses and the like) leads to heartbreak.

Here's what I've noticed: first, there appears to be -- but isn't actually, more on that in a moment -- there appears to be noise on the I/O lines while sounds are playing. This leads to nearly nonstop false triggering. That can be addressed with simple debounce code, but I digress...it shouldn't be appearing in the first place. Let's look at the symptoms though. Nothing unusual should be physically attached, just the Arduino and Wave Shield connected together. Using the default 'pispeak' program as a starting point, a couple of changes: first, in the setup() function, configure the analog pins as inputs with pull-up resistors enabled:

Code: Select all
  int i;
  for(i=14;i<=19;i++) {
    pinMode(i, INPUT);
    digitalWrite(i, HIGH);
  }


Second, modify the playcomplete() function to display any unusual activity on those pins during playback (with the pullups enabled, they should remain continuously HIGH):

Code: Select all
void playcomplete(char *name) {
  uint8_t i;
  playfile(name);
  while (wave.isplaying) {
    for(i=0;i<=5;i++) {
      if(digitalRead(14 + i) == LOW)
        Serial.print((char)('a' + i));
    }
  }
  card.close_file(f);
}


Compile, upload and run the sketch, watching the serial console. Normally what one would expect is each of the digits displayed as it's spoken. Instead (or rather, in addition) I get spurious characters showing unexpected 'stuff' on the input lines.

Okay, so it's just a little interference I figured, and debouncing will take care of it. But the problem is it works both ways: digital output on the I/O lines during audio playback can likewise corrupt transfers to and from the SD card, causing the program to crash severely! (I was trying to scan a keypad, using the digital outputs to drive each row low in succession, and the analog inputs (now set to pull-up-enabled mode and read as digital) to read each column.) If the program behavior is changed so each sound must play in full before keypad scanning is resumed, then no problem. Scanning while playing, bad news.

Long story short, turns out this is not due to electrical interference, but looks rather like a software issue. Though I haven't tracked down a specific culprit yet, it seems as though something in the AF_Wave library may be running out of bounds and clobbering memory normally used by the digitalRead/digitalWrite functions.

The workaround is quite simple: if attempting interruptible sound playback, don't use the digitalRead() or digitalWrite() functions, instead manipulate the port registers directly. This version of playcomplete() reads the analog pins directly via the PINC register and demonstrates that there is in fact no noise present:

Code: Select all
void playcomplete(char *name) {
  uint8_t save,sum;
  save = sum = PINC; // Should be 00111111
  playfile(name);
  while (wave.isplaying)  sum &= PINC; // Accumulate LOW bits
  if(sum != save) // Should still be 00111111
  {
     Serial.println("ZOMG NOISE!");
     Serial.println(sum,BIN);
  }
  card.close_file(f);
}

The keypad scanning code works fine now that I'm using the PORT & PIN registers, even while sound is playing. Interrupting sounds works fine.

For reference, I'm doing this on a stock mega168 Arduino Diecimila, not a 328-upgraded one; it's entirely possible the symptoms only appear in a memory-constrained situation. I'd be curious if folks with either type of chip could try out the above pispeak changes and see if the same symptoms are exhibited.
User avatar
pburgess
 
Posts: 1339
Joined: Sun Oct 26, 2008 1:29 am

Re: Curious Phenomenon with the Wave Shield

Postby adafruit » Fri Oct 31, 2008 1:13 pm

thats odd because ive absolutely used delicate sensors, switches, etc with the wave shield.
try using the 'analog ground' which is the one near the headphone jack

http://www.ladyada.net/make/pumpkin/pumpkin.html

but it would be interesting to see if it is a ram issue. i really do suggest not using serial.println but putstring_nl instead which is ROM based for strings
User avatar
adafruit
 
Posts: 10491
Joined: Thu Apr 06, 2006 3:21 pm
Location: nyc

Re: Curious Phenomenon with the Wave Shield

Postby pburgess » Fri Oct 31, 2008 5:09 pm

Ah ha, here's a much more concise way of demonstrating the issue:

Start with a stock Arduino, stock Wave Shield (e.g. no LED2, digital pins 2-5 used for DAC), stock AF_Wave library and 'pispeak' sketch exactly as downloaded. No buttons or anything else attached.

Modify one line of code in the playcomplete() function. This:

while (wave.isplaying);

becomes:

while (wave.isplaying) digitalWrite(redled,HIGH);

Compile, upload to board and give it a listen. This tickles pin 9 during playback, which should have no effect. But instead, every second or third number gets "chipmunked." digitalWrite() is messing with bits that it should not be. This alternate version, which manhandles the pin on the corresponding PORT directly, has no such problem:

while (wave.isplaying) PORTB |= (1 << (redled - 8));

Looking into it a bit more, I'm not entirely convinced now that it's an AF_Wave problem, but rather might be something in the implementation of digitalWrite() that doesn't play nice with interrupts. I don't know the low-level ins and outs of AVR addressing modes yet, but I've dealt with situations on the Microchip PIC where it may be the case that a C statement like "*foo |= 0x02;" compiles into three instructions: load, modify and store...and if the interrupt (accessing the same address) happens between the read and write, then the interrupt's changes to the register get overwritten upon returning to the mainline code. So perhaps that's what I'm seeing here.

If so, solution 1: avoid digitalRead() or digitalWrite() during audio playback; PIN and PORT manipulation is OK though. Solution 2: modify digitalRead() and digitalWrite(), replacing the arrays and indirection with an ugly switch() statement that accesses the corresponding PIN/PORT registers directly.

Curious if anyone else even has the same problem though. Maybe it's just my own weird little corner of the universe.

Oh yes, and HAPPY HALLOWEEN! RAR!
User avatar
pburgess
 
Posts: 1339
Joined: Sun Oct 26, 2008 1:29 am

Re: Curious Phenomenon with the Wave Shield

Postby adafruit » Fri Oct 31, 2008 7:46 pm

thanks for the excellent feedback/debugging. theres vast amounts of interrupt whacking going on so it sounds likely. what happens if you do
while (wave.isplaying) {
cli();
digitalwrite(9, HIGH);
sei();
}
?
User avatar
adafruit
 
Posts: 10491
Joined: Thu Apr 06, 2006 3:21 pm
Location: nyc

Re: Curious Phenomenon with the Wave Shield

Postby pburgess » Fri Oct 31, 2008 11:06 pm

Wait...you're reading this? Now? Tonight? Halloween! Shouldn't you be out partying or something? Anyway...

The cli()/sei() change does "fix" the problem.

Which should be good news. It would seem like the smoking gun we need to place the blame on interrupts and digitalWrite(). Except no, I had to go complicate matters...

I've been working on a slimmed-down version of AF_Wave. A little smaller, a little faster in places, but starting from the same code so it's essentially the same logic. The curious thing is when I use this version, and keeping the interrupts enabled, the problem does not rear its head! So...same logic, just tighter...that might still suggest a RAM-related issue somewhere in the original library. It's just baffling.

Well, until I can track it down for certain, now there's three workarounds. Thanks for the suggestion!
User avatar
pburgess
 
Posts: 1339
Joined: Sun Oct 26, 2008 1:29 am

Re: Curious Phenomenon with the Wave Shield

Postby adafruit » Fri Oct 31, 2008 11:18 pm

of course, you should post/email the new version when you're done...
User avatar
adafruit
 
Posts: 10491
Joined: Thu Apr 06, 2006 3:21 pm
Location: nyc

Re: Curious Phenomenon with the Wave Shield

Postby pburgess » Sat Nov 01, 2008 1:54 am

Will do!

On a tangent - any idea if the Wave Shield will work with the Arduino Pro? Guessing the 3.3V power wouldn't be a problem, just bypass the voltage regulator on the shield I would think. But what about the 8 MHz aspect? Think it can keep up? This also cuts the SPI frequency in half.
User avatar
pburgess
 
Posts: 1339
Joined: Sun Oct 26, 2008 1:29 am

Re: Curious Phenomenon with the Wave Shield

Postby adafruit » Sat Nov 01, 2008 8:11 am

no way. it absolutely need 16+ mhz.
User avatar
adafruit
 
Posts: 10491
Joined: Thu Apr 06, 2006 3:21 pm
Location: nyc

Re: Curious Phenomenon with the Wave Shield

Postby mtbf0 » Sat Nov 01, 2008 8:28 am

it always makes me cringe to look at this, but here's the source to digitalWrite. since the output is via a bit mask the generated code will indeed be a read/modify/write.

Code: Select all
void digitalWrite(uint8_t pin, uint8_t val)
{
   uint8_t timer = digitalPinToTimer(pin);
   uint8_t bit = digitalPinToBitMask(pin);
   uint8_t port = digitalPinToPort(pin);
   volatile uint8_t *out;

   if (port == NOT_A_PIN) return;

   // If the pin that support PWM output, we need to turn it off
   // before doing a digital write.
   if (timer != NOT_ON_TIMER) turnOffPWM(timer);

   out = portOutputRegister(port);

   if (val == LOW) *out &= ~bit;
   else *out |= bit;
}


it's actually a little worse that r/m/w, because avr-gcc will generate code to read the port, load the bitmask, perform the bitwise operation, and then write the port. not what you'd call an atomic operation.

PORTB |= (1 << (redled - 8 )); will generate a nice sbi, (set bit immediate), iff (redled - 8 ) resolves to a constant expression.

if you'd like to see what avr-gcc is doing to your code avr-objdump is your friend. if you can cd to the directory where arduino has stuck your sketch, the command "avr-objdump -S applet/yoursketchname.elf" will give you a look at the disassembly of your code.

looks like you're having fun. wish i had one of those shields so i could play along.
"i want to lead a dissipate existence, play scratchy records and enjoy my decline" - iggy pop, i need more
User avatar
mtbf0
 
Posts: 1642
Joined: Fri Nov 09, 2007 11:59 pm
Location: oakland ca

Re: Curious Phenomenon with the Wave Shield

Postby pburgess » Mon Nov 03, 2008 8:21 pm

Well, near as I can tell it's a stack overflow problem. The call to digitalRead() or digitalWrite() actually calls a couple of functions deeper...and then if both interrupts trigger (the sample-playing interrupt occurring while the backbuffer-loading interrupt is already in play), the combination of all this just goes too far. Blat.

Disabling interrupts when calling digitalRead() or digitalWrite() is probably the best course of action (that is, cli() before and sei() after). With the alternate scheme of PIN/PORT manipulation...the stack is still perilously close to overflowing. It might've worked in my simple test case but anything more complex that calls a just couple of levels deeper is going to run into the same problems; perhaps this is why another user was having trouble in conjunction with I2C.

Is it possible to change the stack size? I had thought it started at the top of RAM; but if __stack is to believed it begins at address 244. What's up with that?
User avatar
pburgess
 
Posts: 1339
Joined: Sun Oct 26, 2008 1:29 am

Re: Curious Phenomenon with the Wave Shield

Postby adafruit » Mon Nov 03, 2008 10:54 pm

sounds about right, theres 512 bytes + some more used as static audio buffer space
User avatar
adafruit
 
Posts: 10491
Joined: Thu Apr 06, 2006 3:21 pm
Location: nyc

Re: Curious Phenomenon with the Wave Shield

Postby pburgess » Mon Nov 03, 2008 11:56 pm

Bugger. Well if it's indeed the stack then I have a hunch the problem will magically clear up on a mega328. It's odd though...I've tried reducing the size of the play buffers, still had the issues. Whatever...got other stuff on my plate, so cli()/sei() will have to do for now. Thanks for your patience as I fumble through this!
User avatar
pburgess
 
Posts: 1339
Joined: Sun Oct 26, 2008 1:29 am

Re: Curious Phenomenon with the Wave Shield

Postby tcoop25 » Sun Dec 07, 2008 7:41 pm

I am so glad I found this conversation! I have nearly pulled out all of my hair over this very issue. I have a Wave Shield project that also uses an accelerometer, and when a WAV file plays, the accelerometer readings jump all over the place. I was hoping the 328 would fix this issue, but testing with it today showed no change. Using your recommended cli()/sei() fix does keep the accelerometer readings in check, but the WAV file has a lot of static and hiccups. Any other recommendations?

-Tyler
tcoop25
 
Posts: 27
Joined: Thu May 08, 2008 9:00 am

Re: Curious Phenomenon with the Wave Shield

Postby pburgess » Fri Dec 12, 2008 2:38 pm

Tyler: if you're comfortable reading/writing the PORT and PIN registers directly (while leaving interrupts enabled), this is the only way I know to simultaneously get error-free readings and hiccup-free playback. See the 'Port Manipulation' page on the Arduino web site for guidance:

http://www.arduino.cc/en/Reference/PortManipulation

Another solution that occurs to me is that alternative pin read/write functions (using the same syntax with a different name) could be added to the AF_Wave library; the source of the trouble appears to be that the digitalRead/Write functions in the standard wiring library in turn call error-checking functions that nest another two or three stack levels deep, causing an overflow. If these checks were simply inlined (and/or some of the overly-pedantic error checks removed), this might avoid these gas pains.
User avatar
pburgess
 
Posts: 1339
Joined: Sun Oct 26, 2008 1:29 am

Re: Curious Phenomenon with the Wave Shield

Postby tcoop25 » Wed Dec 17, 2008 5:15 pm

pburgess, thanks for the tip. While the port manipulation is way over my head, I really have no choice but to give it a shot as it is the only thing standing in the way of me finishing my project. I will try your second option first, as it seems like it would be a lot easier to implement. Will report back with my findings...

-TC
tcoop25
 
Posts: 27
Joined: Thu May 08, 2008 9:00 am

Next

Return to Arduino Shields from Adafruit

Who is online

Users browsing this forum: Google [Bot] and 5 guests

Stuff to buy from the Adafruit store and links to product documentation!


New Products [103]

Raspberry Pi[80]
 
FLORA[23]
 
Bunnie Studios[9]
 
FPGA[1]
 
mbed[11]
Arduino[60]
 
NETduino[14]
 
BeagleBone[24]
 
Android[6]
 
XBee[10]
More Dev Boards[30]


 
BoArduino[8]
 
SpokePOV[4]
 
TV-B-Gone[4]
 
MiniPOV[3]
 
SIM reader[3]
 
Microtouch[5]
 
Clocks & Watches[18]
 
Drawdio[4]
 
Brain Machine[1]
 
Game of Life[2]
 
MintyBoost[2]
More DIY Kits[16]


 
MaKey MaKey[3]
 
Tweet-a-Watt[5]
 
Young Engineers[33]
 
Discover Electronics[2]
 
Snap Circuits[4]
 
littleBits[3]
 
Project packs[8]


 
Breakout Boards[33]
LCDs & Displays[48]
Components & Parts[69]
Batteries & Power[49]
EL Wire/Tape/Panel[52]
LEDs[109]
 
Wireless[14]
Cables[61]
 
Lasers[6]
Sensors/Parts[145]
 
Enclosures/Cases[11]
 
Solar[11]
 
RFID / NFC[13]
Prototyping[70]
 
iDevices[13]
Tools[71]
 
Wearables[39]
 
CNC[37]
 
Robotics[29]
 
3D printing[1]
 
Materials[24]


 
Stickers[41]
 
Skill badges[55]
 
Books[25]
 
Circuit Playground[7]
 
Gift Certificates[4]