Serial output - Is there a better way to do this?
Jeff Haas
Posts: 431
I'm learning Spin having moved over from PBasic, and I've got one of the inexpensive Catalex MP3 players mentioned in another thread. It works fine with this code:
However, I can't figure out how to represent all the serial commands on a single line. It's easy on the BS2:
What's the best way to do this? I tried out the other commands in FullDuplexSerial but couldn't get them to work. And I've looked through lots of the other serial methods in the OBEX but can't find what I want.
{
Catalex mp3 board sound test
10/17/2015
One MP3 in a folder named 01 on MicroSD card.
}
CON
_clkmode = xtal1 + pll16x ' Crystal and PLL settings.
_xinfreq = 5_000_000 ' 5 MHz crystal x 16 = 80 MHz
OBJ
Serial : "FullDuplexSerial"
PUB Go
serial.start(2, 3, %0000, 9_600)
Serial.Tx($7E) ' Init the Catalex MP3 player
Serial.Tx($FF)
Serial.Tx($06)
Serial.Tx($0C)
Serial.Tx($00)
Serial.Tx($00)
Serial.Tx($00)
Serial.Tx($EF)
waitcnt(clkfreq + cnt) ' Wait 1 second
waitcnt(clkfreq + cnt) ' Wait 1 second
Serial.Tx($7E) ' Select TF socket
Serial.Tx($FF)
Serial.Tx($06)
Serial.Tx($09)
Serial.Tx($00)
Serial.Tx($00)
Serial.Tx($02)
Serial.Tx($EF)
waitcnt(clkfreq + cnt) ' Wait 1 second
Serial.Tx($7E) ' Set volume to 15
Serial.Tx($FF)
Serial.Tx($06)
Serial.Tx($06)
Serial.Tx($00)
Serial.Tx($00)
Serial.Tx($0F)
Serial.Tx($EF)
waitcnt(clkfreq + cnt) ' Wait 1 second
Serial.Tx($7E) ' Play song 1 in folder 1
Serial.Tx($FF)
Serial.Tx($06)
Serial.Tx($0F)
Serial.Tx($00)
Serial.Tx($01)
Serial.Tx($01)
Serial.Tx($EF)
However, I can't figure out how to represent all the serial commands on a single line. It's easy on the BS2:
SEROUT MP3, 84, [$7E,$FF,$06,$09,$00,$00,$02,$EF] 'Select TF socket
What's the best way to do this? I tried out the other commands in FullDuplexSerial but couldn't get them to work. And I've looked through lots of the other serial methods in the OBEX but can't find what I want.

Comments
One way to do it is with byte arrays in a DAT section:
PUB Go ... CatalexCmd(@MP3Init) CatalexCmd(@Volume) 'set volume to 15 ... Volume[6] := 3 CatalexCmd(@Volume) 'set volume to 3 PRI CatalexCmd(pntr) : i repeat i from 0 to 7 Serial.Tx(byte[pntr][i]) DAT MP3Init byte $7E,$FF,$06,$0C,$00,$00,$00,$EF Volume byte $7E,$FF,$06,$06,$00,$00,$0F,$EFAs you see, you can also modify the byte data very easy before you send a command.Andy
Thanks! That was just what I needed. I'm still getting my head around the whole object and method-oriented way of doing things.
FYI, after some experimentation, for anyone else interested in using the Catalex board, the MP3Init sequence is not needed. You just need these:
Then you can select both the MP3 to play and the folder using these commands, as Andy shows above:
Jeff
which thread are you referring? Just curious
http://forums.parallax.com/discussion/161245/erco-here-s-the-cheap-mp3-modules
Since I don't have one and I wanted others to be able to reference the Schmarschmino demos the vendor provides, I used their named constants. Once I get a player and understand what each thing does, I may rename things. Note, too, that all of the demos show no feedback from the player and a baud rate of 9600. This can be done with a single pin and a method; no serial cog is required.
PUB txStrEsc(str) | temp repeat while temp := BYTE[ str++ ] ' repeat as long as byte isn't zero if temp == $7F ' escape byte is $7F if (temp := BYTE[ str++ ]) => $80 ' get escaped byte value Serial.Tx(temp & $7F) ' strip high order bit for transmission else ' A $7F must not be followed by a byte less than $80 quit ' This is so a string ending with $7F will terminate properly else Serial.Tx(temp)To transmit the example shown for the BS2, do:
txStrEsc( string( $7E, $FF, $06, $09, $7F, $80, $7F, $80, $02, $EF ) )
A $7F is followed by the byte to be sent with its high order bit set. To send $00, use $7F,$80. To send $7F, use $7F,$FF. There's a check for the case where a $7F is the last byte in a string.
PUB StrN(stringptr,nchar) '' Send counted string repeat nchar tx(byte[stringptr++])Then as Jon suggests, in the application give each function a meaningful name that calls the generic StrN. Or, simply give each string a name that reveals its function.void sendCommand(int8_t command, int16_t dat) { delay(20); Send_buf[0] = 0x7e; // Send_buf[1] = 0xff; // Send_buf[2] = 0x06; // Send_buf[3] = command; // Send_buf[4] = 0x00;// Send_buf[5] = (int8_t)(dat >> 8);//datah Send_buf[6] = (int8_t)(dat); //datal Send_buf[7] = 0xef; // for(uint8_t i=0; i<8; i++)// { mySerial.write(Send_buf[i]) ; } }I didn't think it was necessary to stick the bytes into a buffer before sending -- at 9600 baud a few microseconds here and there between bytes should be fine.
pri send_command(cmd, value) delay(20) tx($7E) tx($FF) tx($06) tx(cmd) tx($00) tx(value.byte[1]) tx(value.byte[0]) tx($EF) pri delay(ms) | t t := cnt repeat ms waitcnt(t += clkfreq/1000) pri tx(b) | t ' borrowed from Simple Serial '' True mode output of byte b b := (b | $FF00) << 2 ' add stop bit(s), start bit t := cnt ' sync bit timer repeat 10 ' start + 8 bits + stop waitcnt(t += bitticks) ' hold for bit timing outa[txp] := b >>= 1 ' output next bitThat demo commands disable response from the device so I kept it to one pin. Since coms is the very tame speed of 9600 baud, I was able to borrow (with some clean-up) serial output from Simple Serial.
I set up six buttons as the schematic in the original file here in the OBEX shows. Those aren't shown below because some characters don't display properly in the forum.
'' ================================================================================================= '' '' File....... jm_debounce_catalex_mp3.spin '' Purpose.... Debounces inputs, sends commands to Catalex MP3 player '' Updated.... 20 OCT 2015 '' '' ================================================================================================= con _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 con BTN_UP = %000001 << 18 ' for JM LCD UI board BTN_DN = %000010 << 18 BTN_LF = %000100 << 18 BTN_RT = %001000 << 18 BTN_OK = %010000 << 18 BTN_ESC = %100000 << 18 BTN_MASK = BTN_UP | BTN_DN | BTN_RT | BTN_LF | BTN_OK | BTN_ESC ACT_HI = 1 ACT_LO = 0 obj btns : "jm_debounce" catalex : "jm_catalex_mp3" var pub main | b catalex.setup(3) ' TX pin to Catalex is pin 3 btns.init(BTN_MASK, 25, ACT_HI) repeat if btns.getbits(BTN_ESC) catalex.stop b := btns.getbits(BTN_MASK) & !BTN_ESC ' all but Esc case b BTN_UP : catalex.play_from_folder(2,1) ' LCD commands in original replaced with these commands for testing BTN_DN : catalex.next_song BTN_LF : catalex.previous_song BTN_RT : catalex.volume_up BTN_OK : catalex.volume_down waitcnt(clkfreq / 10 + cnt)