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.


