SparkFun Forums 

Where electronics enthusiasts find answers.

Have questions about a SparkFun product or board? This is the place to be.
By Maleche
#99159
It took awhile but here is the WORKING code for the SOMO-14D and Arduino. It is translated from the 4dsystems AVR code. Most credit goes to them.
It uses bit-banging technique. ShiftOut does not work (well) for two reasons (1) ShiftOut is 8bit and the SOMO uses 16bit words, with a data packet of 32 bits total. (2) The clock width when using ShiftOut is roughly 2us and SOMO requires 200us width.

I hope Sparkfun can use this and distribute it with the SOMO. The code might be a little weak (still learning)

ENJOY!!
Doyle

/*************************************************
* Filename: SOMODuino
* Created: 18 April 2010
* Author: Doyle Maleche -> maleche1 at comcast dot net
* Description: Arduino code to test the SOMO-14D with Serial
* Modifed code from 4dsystems to work with Arduino
* Version: 0.1
**************************************************/
//
// Use HyperTerminal or any Terminal program to benefit from the screen refresh
// This code is works with the Arduino
// Please let me know of any updates you may add so I can learn from it.

const unsigned int minVol= 0xfff0; // Minimum volume
const unsigned int maxVol= 0xfff7; // Max Volume
const unsigned int PlyPse = 0xfffe; // Play or Pause
const unsigned int Stop= 0xFFFF; // Stop
const int pinClock= 3;
const int pinData =4;
const int pinBusy =6;
const int pinReset=7;
unsigned int volLevel=0x0005;
int Song; // current Song
unsigned int vol; // current volume


void setup(){
Serial.begin(9600);
pinMode(pinData,OUTPUT); // set pin 4 to output for Data
pinMode(pinClock,OUTPUT); // set pin 3 to output for data
pinMode(pinReset,OUTPUT); // set pin 7 to allow software reset
pinMode(pinBusy,INPUT); // set pin 6 to monitor while Song is playing
Reset();
}

void loop()
{
int cmd;
if (Serial.available()>0) {
cmd=Serial.read(); // Read the user command
delay(10);
Serial.println(cmd,BYTE); // Print user selection
// Check user input command. You could use the CASE/SWITCH function here instead of IF
if (cmd==110){nextPlay();} //"n" =Play Next Song
if (cmd==112){pausePlay();} //"p" =Pause/Play
if (cmd==116){stopPlay();} //"t" = Stop Play
if (cmd==115){PlaySong();} //"sx"; x=Play Song Number
if (cmd==105){incVol();} //"i" = Increase Volume
if (cmd==100){decVol();} //"d" = Decrease Volume
if (cmd==114){Reset();} //"r" = Reset
if (cmd==99){CycleSongs();} //"c" = Cycle through all Songs

delay(2000); // Pause 2 seconds to show User selection
Menu(); //Refresh Menu
}

}

void Menu()
{
Serial.print(12,BYTE); // Clear terminal. Works with real terminal programs like HyperTerminal. Ardunio's serial monitor will not clear.
Serial.println("*************************************");
Serial.println("* SOMO-14D *");
Serial.println("* Arduino Serial controlled *");
Serial.println("* Test and Evaluation *");
Serial.println("*************************************");
Serial.println();
Serial.println("n = Play Next Song");
Serial.println("p = Pause or Play current Song");
Serial.println("t = Stop current Song");
Serial.println("sxxx = Play Song number 000 - 511");
Serial.println("i = Increase Volume");
Serial.println("d = Decrease Volume");
Serial.println("c = Cycle through all Songs");
Serial.println("r = Reset SOMO and goto sleep");
Serial.println("=====================================");
Serial.print("Enter command > ");
}


/**********************************************************************************
Send Sequence
**********************************************************************************/

void sendData(int ThisSong)
{
int TheSong = ThisSong;
int ClockCounter=0;
int ClockCycle=15;//0x0f;

digitalWrite(pinClock,HIGH); // Hold (idle) for 300msec to prepare data start
delay(300);
digitalWrite(pinClock,LOW); //Hold for 2msec to signal data start
delay(2); //2msec delay

while(ClockCounter <= ClockCycle)
{ digitalWrite(pinClock,LOW);
if (TheSong & 0x8000)
{digitalWrite(pinData,HIGH);
}
else
{digitalWrite(pinData,LOW);
}
TheSong = TheSong << 1;
delayMicroseconds(200); //Clock cycle period is 200 uSec - LOW
digitalWrite(pinClock,HIGH);
ClockCounter++;
delayMicroseconds(200); //Clock cycle period is 200 uSec - HIGH
}

digitalWrite(pinData,LOW);
digitalWrite(pinClock,HIGH); // Place clock high to signal end of data
}

/**********************************************************************************
Plays Stored Song by Number
**********************************************************************************/

void PlaySong()
{ sendData(Stop);
int input[3];
int Index=0;
Serial.print("Enter Song Number (000-511): " );
Serial.flush();

do
{ if(Serial.available()> 0) //Wait for each number input
{
Index++; // Increment input array index
input[Index]=Serial.read()-48; // assign number to input array (ASCII value - 48 returns 0 through 9)
Serial.print(input[Index]); // Print each number
Serial.flush(); // Clear serial buffer to reset Serial.available to 0
}
}
while (Index < 3); // Count each number until three are entered (000 to 511)
int SongNumber=input[1]*100 + input[2] *10 + input[3]; // Add the numbers in the correct decimal order
delay(5);
if (SongNumber >= 512 || SongNumber <0){ // Warn if song number is not within range limit
Serial.print(SongNumber);
Serial.println(" is not within 0 and 511");}

if (SongNumber >= 0 && SongNumber < 512){ // Song is within range limit
Serial.print("-> Song No.");
Serial.println(SongNumber);
sendData(SongNumber);}

}

/**********************************************************************************
Plays the next Song in the Sequence
**********************************************************************************/
void nextPlay()
{
if (Song >= 0 && Song < 512){ Song++;} // should be within the 511 number range
if (Song >= 512 || Song <0){ Song=0;}
Serial.print("Song No.");
Serial.println(Song);
sendData(Song);
}


/**********************************************************************************
Play/Pause function, play or pause the Song
**********************************************************************************/
void pausePlay()
{
Serial.println("Play/Pause.");
sendData(PlyPse);
}

/**********************************************************************************
Stop Song
**********************************************************************************/
void stopPlay()
{
Serial.println("Stop.");
sendData(Stop);
}

/**********************************************************************************
Increase Volume
**********************************************************************************/
void incVol()
{
if (vol >= minVol && vol < maxVol){ vol++;} // should be within the volume range
if (vol >= maxVol | vol <minVol){ vol=maxVol;}
int tVol=vol; // Temp Volume
volLevel = tVol - 0xfff0;
Serial.print("Increase volume.=");
Serial.println( volLevel);
sendData(tVol);

}
/**********************************************************************************
Decrease Volume
**********************************************************************************/
void decVol()
{
if (vol > minVol && vol <= maxVol){ vol--;} // should be within the volume range
if (vol >= maxVol | vol <minVol){vol=maxVol;}
int tVol=vol; // Temp Volume
volLevel = tVol-0xfff0; // levels are from 0 to 7. volume code is fff0 - fff7
Serial.print("Decrease volume.");
Serial.println(volLevel);
sendData(tVol);
}

/**********************************************************************************
Reset SOMO
**********************************************************************************/
void Reset()
{
//Serial.println("RESET.");
digitalWrite(pinReset,LOW);
delay(50);
digitalWrite(pinReset,HIGH);
Song=0;
Menu();
}

/**********************************************************************************
Cycle Through and play all sound files
**********************************************************************************/
void CycleSongs()
{int Busy=0;
long Start=0;
for(Song=0;Song< 512;Song++) //Start with file 0 end with file 511
{
Start=0; //Reset Start timer
Serial.print("Cycle Song=");
Serial.println(Song);
Start=millis(); // Set Start timer to current clock cycle (internal to MCU)
sendData(Song); // Play current Song
delay(50); // Wait for BUSY signal (LED) to initialize
do // Start wait loop
{
Busy =digitalRead(pinBusy); // Read Busy pin status. While Song is playing, Busy == 1
}
while(Busy !=0); // Keep reading Busy pin until end of Song. Busy == 0
if (millis()-Start < 900){break;} // Test if we are at the last song
// if the difference between the current MCU timer and Start timer is < 900ms,
// we are at end or the Song is too short. Exit the FOR/LOOP

}
Song=0; // reset song number to 0
Menu(); // refresh display
}
void RandomSongs()
{
Serial.print("Work in progress");
}
By popkalab
#127511
Hey,

I have 6 diferent sensors (switches) connected to 6 direrents analog input in my arduino.

I want that when each of the switches are activated a diferent sound file is played. one of the switched is to stop all the sounds.

I am wondering how should I wire this. Do you have any tips?

another question is about the code. any tips?

Thanks!

Ricardo
By Maleche
#127573
Hello Ricardo,

Instead of entering the file (sound) number as "002", "004", etc, you can monitor your switches and program the following;

#define pin9 9
#define pin10 10

setup()
{
pinMode(pin9,INPUT); // set pin 9 to input
pinMode(pin10, INPUT); // set pin 10 to input
digitalWrite(pin9,HIGH); // turn on internal pullup resister on pin 9
digitalWrite(pin10,HIGH); // turn on internal pullup resister on pin 10
}
loop()
{
if(pin9==0){sendData(001);} // Play sound in file 1 if sw1 is LOW
if(pin10==0){sendData(002);} // Play sound in file 2 if sw2 is LOW
delay(200); // allow processing time
}
Instead of using analog ports for your switches, use digital
This should get you in the right area.
By popkalab
#132265
Thank you very much for the tip. It worked quite well...

I have now another question. I want to address one sound file for each single key in a keyboard. In this way when I press the letter "A" the sound equivalent will be triggered. I managed to make with one button to test and it works.

The problem is that takes about 1 or 2 seconds for the file to play and I would like that it plays immediately after the button is pressed.

Someone know what is the matter and how to solve it?

Here is the code:

/*************************************************
Based on code for the SOMO-14D by Doyle Maleche
**************************************************/

// this is the button that tests the code
// we don't need this in the final version
int buttonPin = 12;
int buttonState;

//const unsigned int minVol= 0xfff0; // Minimum volume
//const unsigned int maxVol= 0xfff9; // Max Volume
//const unsigned int PlyPse = 0xfffe; // Play or Pause
const unsigned int Stop= 0xFFFF; // Stop
const int pinClock= 3;
const int pinData =4;
//const int pinBusy =6;
const int pinReset=7;
unsigned int volLevel=0x0007;
int Song; // current Song
unsigned int vol; // current volume

// put all the letters in an array so they can be used by the yarnMotor
char alphabet[26] = {
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'};

void setup(){
Serial.begin(9600);
pinMode(pinData,OUTPUT); // set pin 4 to output for Data
pinMode(pinClock,OUTPUT); // set pin 3 to output for data
pinMode(pinReset,OUTPUT); // set pin 7 to allow software reset
// pinMode(pinBusy,INPUT); // set pin 6 to monitor while Song is playing
Reset();
}

void loop() {
// read the button to trigger the sound
buttonState = digitalRead(buttonPin);
Serial.println(buttonState);

if (buttonState == 1) {
// this is the function that will be triggered by the keyboard
PlaySong('S');
delay(2000); // Pause 2 seconds so that file has enough time to play - maybe we can make this a bit shorter?
}
}

/**********************************************************************************
* Send Sequence
**********************************************************************************/
void sendData(int ThisSong)
{
int TheSong = ThisSong;
int ClockCounter=0;
int ClockCycle=15;//0x0f;

digitalWrite(pinClock,HIGH); // Hold (idle) for 300msec to prepare data start
delay(300);
digitalWrite(pinClock,LOW); //Hold for 2msec to signal data start
delay(2); //2msec delay

while(ClockCounter <= ClockCycle)
{
digitalWrite(pinClock,LOW);
if (TheSong & 0x8000)
{
digitalWrite(pinData,HIGH);
}
else
{
digitalWrite(pinData,LOW);
}
TheSong = TheSong << 1;
delayMicroseconds(200); //Clock cycle period is 200 uSec - LOW
digitalWrite(pinClock,HIGH);
ClockCounter++;
delayMicroseconds(200); //Clock cycle period is 200 uSec - HIGH
}

digitalWrite(pinData,LOW);
digitalWrite(pinClock,HIGH); // Place clock high to signal end of data
}

/**********************************************************************************
* Plays Stored Song by Number
**********************************************************************************/
void PlaySong(char test)
{
sendData(Stop);
for (int count = 0; count < sizeof(alphabet); count++) {
if (test == alphabet[count]) {
sendData(count);
}
}
}

/**********************************************************************************
* Reset SOMO
**********************************************************************************/
void Reset()
{
//Serial.println("RESET.");
digitalWrite(pinReset,LOW);
delay(50);
digitalWrite(pinReset,HIGH);
Song=0;
}

Best,

Ricardo
By Maleche
#132277
If your sound file takes too long to start, you should use Audacity (free ware) to edit out the blank (silence) from the sound file and while you are at it, cut out the ending silence and save the file again.

Since the letter 'A' is ASCII 65, just subtract the value from 64. It will leave you with 1 for A, 2 for B, etc.

Regards
By popkalab
#132315
Thank you.

I already cut the sound files with Audacity and erased the empty space before the sound. However there is still a big delay from when the button is pressed till the sound starts.

I guess it is nothing to do with the sound files but with the Somo. Do you have any idea what could be done to improve that? Any tricks?
By Maleche
#132339
Try removing
delay(2000); // Pause 2 seconds so that file has enough time to play - maybe we can make this a bit shorter?

you are stopping all processes until this delay has finished (2 seconds).
By popkalab
#132448
Hey. i changed the sim card and works better now. The funny thing is that i am using a Sandisk 2Gb and I changed for the same brand and size. This Somo is very tricky with the sim cards ;-(

Anyway... it is better now. Thanks for your help!!!!
By aurel741
#140516
hey I m new in this site and I m not native english so excuse me for all of mistakes.

My question is simple the somo 14d can play 2 diferent sound in same time?
for example a long song with little sound like shot guns?

thanks for your help.
By Maleche
#140520
Unfortunatley it can not play 2 sounds simultaneously. You could use 2 modules and have them trigger selected sound files. Parallel the 2 modules communication pins together and program conditions for each to play the associated sound file. Considers using an Arduino Mega to even control 4wheelchair modules. This would also allow MANY external trip switches.
good luck!
By Ronn0011
#144950
Hi Maleche, I am not sure if my Sound Module is same as yours, Here is the link
http://i278.photobucket.com/albums/kk11 ... 1713PM.png
Image
I try upload this program so far working
const int clockPin = 2; // the pin number of the clock pin
const int dataPin = 3; // the pin number of the data pin
const int resetPin = 4; // the pin number of the reset pin

const unsigned int VOLUME_0 = 0xFFF0;
const unsigned int VOLUME_1 = 0xFFF1;
const unsigned int VOLUME_2 = 0xFFF2;
const unsigned int VOLUME_3 = 0xFFF3;
const unsigned int VOLUME_4 = 0xFFF4;
const unsigned int VOLUME_5 = 0xFFF5;
const unsigned int VOLUME_6 = 0xFFF6;
const unsigned int VOLUME_7 = 0xFFF7;

const unsigned int PLAY_PAUSE = 0xFFFE;
const unsigned int STOP = 0xFFFF;

void setup() {
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);
pinMode(resetPin, OUTPUT);

digitalWrite(clockPin, HIGH);
digitalWrite(dataPin, LOW);

// reset the module
digitalWrite(resetPin, HIGH);
delay(100);
digitalWrite(resetPin, LOW);
delay(10);
digitalWrite(resetPin, HIGH);
delay(100);

sendCommand(VOLUME_7);
}

void loop() {
// play "0000.ad4"
sendCommand(0x0000);
delay(100000);

// play "0001.ad4"
sendCommand(0x0001);
delay(10000);

// stop playing
sendCommand(STOP);
delay(1000);
}

void sendCommand(unsigned int command) {
// start bit
digitalWrite(clockPin, LOW);
delay(2);

// bit15, bit14, ... bit0
for (unsigned int mask = 0x8000; mask > 0; mask >>= 1) {
if (command & mask) {
digitalWrite(dataPin, HIGH);
}
else {
digitalWrite(dataPin, LOW);
}
// clock low
digitalWrite(clockPin, LOW);
delayMicroseconds(200);

// clock high
digitalWrite(clockPin, HIGH);
delayMicroseconds(200);
}

// stop bit
delay(2);
},

however, it takes long to play the song: I am currently connecting pin 2,3,and 4 from arduino to SOMO

I also would like to test your code, to play song with keyboard key, however, It does not work and I would like to check if my wiring is right

http://s278.photobucket.com/albums/kk11 ... 0118PM.mp4
By Ronn0011
#144951
Is this code by right if I press 1, it should play song 0

/*************************************************
viewtopic.php?f=14&t=21388
* Filename: SOMODuino
* Created: 18 April 2010
* Author: Doyle Maleche -> maleche1 at comcast dot net
* Description: Arduino code to test the SOMO-14D with Serial
* Modifed code from 4dsystems to work with Arduino
* Version: 0.1
**************************************************/
//
// Use HyperTerminal or any Terminal program to benefit from the screen refresh
// This code is works with the Arduino
// Please let me know of any updates you may add so I can learn from it.

const unsigned int minVol= 0xfff0; // Minimum volume
const unsigned int maxVol= 0xfff7; // Max Volume
const unsigned int PlyPse = 0xfffe; // Play or Pause
const unsigned int Stop= 0xFFFF; // Stop
const int pinClock= 2;
const int pinData =3;
//const int pinBusy =3;
const int pinReset=4;


unsigned int volLevel=0x0005;
int Song; // current Song
unsigned int vol; // current volume


void setup(){
Serial.begin(9600);
pinMode(pinData,OUTPUT); // set pin 4 to output for Data
pinMode(pinClock,OUTPUT); // set pin 3 to output for data
pinMode(pinReset,OUTPUT); // set pin 7 to allow software reset
//pinMode(pinBusy,INPUT); // set pin 6 to monitor while Song is playing

}

void loop()
{
int cmd;
if (Serial.available()>0) {
cmd=Serial.read(); // Read the user command
delay(10);
Serial.println(cmd,BYTE); // Print user selection
// Check user input command. You could use the CASE/SWITCH function here instead of IF
if (cmd==1){ (0x0000);} //"1" =Play Song 0
if (cmd==2){(0x0001);} //"2" =Pause Song 2
if (cmd==3){(0xFFFF);} //"3" = Stop Play
if (cmd==115){(0xFFFE);} //"sx"; x=Play Song Number


delay(2000); // Pause 2 seconds to show User selection

Menu(); //Refresh Menu

}
}
void Menu()
{
Serial.print(12,BYTE); // Clear terminal. Works with real terminal programs like HyperTerminal. Ardunio's serial monitor will not clear.
Serial.println("*************************************");
Serial.println("* SOMO-14D *");
Serial.println("* Arduino Serial controlled *");
Serial.println("* Test and Evaluation *");
Serial.println("*************************************");
Serial.println();
Serial.println("1 = PlaySong 1");
Serial.println("p = Pause or Play current Song");
Serial.println("2 = Stop current Song");
Serial.println("sxxx = Play Song number 000 - 511");
Serial.println("i = Increase Volume");
Serial.println("d = Decrease Volume");
Serial.println("c = Cycle through all Songs");
Serial.println("r = Reset SOMO and goto sleep");
Serial.println("=====================================");
Serial.print("Enter command > ");
}
/**********************************************************************************
Send Sequence
**********************************************************************************/

void sendData(int ThisSong)
{
int TheSong = ThisSong;
int ClockCounter=0;
int ClockCycle=15;//0x0f;

digitalWrite(pinClock,HIGH); // Hold (idle) for 300msec to prepare data start
delay(300);
digitalWrite(pinClock,LOW); //Hold for 2msec to signal data start
delay(2); //2msec delay

while(ClockCounter <= ClockCycle)
{ digitalWrite(pinClock,LOW);
if (TheSong & 0x8000)
{digitalWrite(pinData,HIGH);
}
else
{digitalWrite(pinData,LOW);
}
TheSong = TheSong << 1;
delayMicroseconds(200); //Clock cycle period is 200 uSec - LOW
digitalWrite(pinClock,HIGH);
ClockCounter++;
delayMicroseconds(200); //Clock cycle period is 200 uSec - HIGH
}

digitalWrite(pinData,LOW);
digitalWrite(pinClock,HIGH); // Place clock high to signal end of data
}


It does not work, however i see the light on arduinno RX is blinking when i send command 1, however the song is not played, Can please help me with the wiring
By Maleche
#144988
The code takes 3 digit song file:
if (cmd==1){ (0x000);} //"1" =Play Song 0 -> this should be 3 digit song/file name "000.xxx"
if (cmd==2){(0x001);} //"2" =Pause Song 2 -> Send the pause command per my code
if (cmd==3){(0xFFFF);} //"3" = Stop Play -> Send the Stop/Play command per my code
if (cmd==115){(0xFFFE);} //"sx"; x=Play Song Number -> This is "s" followed by the 3 digit sequence song file

*** I also noted that when you load the songs on the SD card, you need to copy and paste them all at once, not separately. The file names need to be ordered in the sequence you want to address. 000.xxx, 001.xxx, 003.xxx, 002.xxx, 004.xxx
***file 003.xxx is not file 002.xxx and file 002.xxx is not file 003.xxx. The order in which you copy and paste is the order the SOMO "thinks" you want and not the file-name sequence.
I hope this helps.