PICAXE-18X + VMUSIC2 using SPI

Phockzie

New Member
Hi everyone, i'm new to this forum and i'm a picoholic.

I have been working to create a project that does something like this...

Reads from a file on a USB Flash stick plugged into the VMUSIC2 using bitbanged SPI
Writes the contents of that file to a 24LC1025 using I2C
Starts to play an MP3 on the USB Flash stick
Controls an I2C IO chip with the contents of the 24LC1025 (taken from the file on the USB)

This all works, which i'm very proud of as it's only an 18X :D

The problem was when the MP3 is playing, sound is interrupted every second until I get the SPI data containing the "Played Time" out of the SPI buffer. Has anyone come across this problem, and can I stop the VMUSIC2 module from sending this data whilst playing the MP3, or at least stop it interrupting playback? This doesn't happen when the UART mode, but I can't use UART mode in my project.

Thank you.
 
Last edited:

goom

Senior Member
I cannot help with your problem, but would very much like to see your code for the SPI communication. Any chance of posting it? From what I have read elsewhere, you have solved a rather tricky problem.
 

Phockzie

New Member
VMUSIC2 SPI code

I hope this helps people, it took a while to write. It took even longer to discover that the SPI CLOCK is active low not active high as it says in the VMUSIC2 manual.

It's not brilliant coding but it works and it's fairly small.

If i can get more people using the SPI (which is brilliant for the PICAXE processors) instead of the UART which is uncontrollable in software, someone might be able to work out my problem of the MP3 being interrupted when the "Time code" is waiting to be read on the SPI bus.

If you use this code in anything and make a fortune, think of me, and my kids that need new shoes :rolleyes: and my wife that needs a new kitchen ;)

Code:
Symbol X = B6
Symbol N = B7
Symbol D = B8
Symbol SPI_RW = Bit0 '0 = Write, 1 = Read
Symbol SPI_OK = Bit1 '0 = Success, 1 = Failure
Symbol SPI_Read = 1
Symbol SPI_Write = 0
Symbol SPI_CS = Output5
Symbol SPI_CLK = Output6		' The VMUSIC clock is active low, not active high as in the manual
Symbol SPI_DO = Output7
Symbol SPI_DI = Input7


MAIN:
    Pause 1000
    sertxd("Starting",CR,LF)		' Show status via debug terminal
    low SPI_CS
    gosub SPI_WaitForPrompt		' wait for VMUSIC2 Prompt on the SPI bus (">", CR) after initialisation
    sertxd("Disk found",CR,LF)		' Show status via debug terminal
    d = $91 ' IPH			' VMUSIC2 Short Command for hex input / output
    gosub SPI_SendCmdCR
    gosub SPI_EmptyRX			' Empty RX Buffer
    d = $10 ' SCS			' VMUSIC2 Short Command for "Short Command Mode"
    gosub SPI_SendCmdCR	
    gosub SPI_EmptyRX

    gosub vm2_Playmp3			' Play a tune

    end


vm2_Playmp3:
    d = $1D 				' VMUSIC2 Short command for Play Music File
    gosub SPI_SendCmd
    d = $20
    gosub SPI_SendCmd
    d = "1"
    gosub SPI_SendCmd
    d = "."
    gosub SPI_SendCmd
    d = "m"
    gosub SPI_SendCmd
    d = "p"
    gosub SPI_SendCmd
    d = "3"
    gosub SPI_SendCmd
    d = CR
    gosub SPI_SendCmd
    gosub SPI_EmptyRX
    return    
        
SPI_SendCmdCR:			' SPI Send the byte in "D" to the SPI bus then send a "CR" to the bus
    gosub SPI_SendCmd
    D = CR
    gosub SPI_SendCmd
    return

SPI_SendCmd:			' SPI Send the byte in "D" until a "Status OK" is seen
    SPI_RW = SPI_Write
    do
        gosub SPI_GO
    loop until SPI_OK = 0
    return

SPI_EmptyRX:			' Read the SPI buffer until status bit is 1 to clear it
    SPI_RW = SPI_Read
    do
        gosub SPI_GO
    loop until SPI_OK = 1
    return    

SPI_WaitForPrompt:		' subroutine which waits for the prompt from the VMUSIC2 (">", CR)
    d = ">"
    gosub SPI_WaitForD
    d = CR
    gosub SPI_WaitForD
    return
    
SPI_WaitForD:			' Keep reading the SPI bus until the character in "D" is seen
    SPI_RW = SPI_Read
    do
        do
            gosub SPI_GO
        loop until SPI_OK = 0
    loop until X = D
    return

SPI_GO:				' bitbang the VMUSIC2 SPI bus
				' Entry - D = Byte to write to SPI bus, SPI_RW = either SPI_Write or SPI_Read
				' Exit = X = Byte Read from SPI bus, SPI_OK = either 0 or 1 depending on success status
    if SPI_RW = SPI_Write then 	
        X = D 
    end if
    low SPI_CS
    high SPI_CS	
    high SPI_DO 		' SPI Start bit
    low SPI_CLK
    high SPI_CLK
    if SPI_RW = SPI_WRITE then
        low SPI_DO		' SPI Read Status Bit
    else
        high SPI_DO 		' SPI Write Status Bit
    end if
    low SPI_CLK
    high SPI_CLK
    low SPI_DO 			' SPI "ADD" 0 = data 1 = REGISTER
    low SPI_CLK
    high SPI_CLK
    gosub SPI_IO
    low SPI_CLK
    SPI_OK = SPI_DI 		' Success?
    high SPI_CLK
    low SPI_CS
    low SPI_DO
    return
 
SPI_IO:				' 8 bit bitbang routine
    for N = 0 to 7
        if X > 127 Then SPI_IO_1
        low SPI_DO
        goto SPI_IO_0
SPI_IO_1:
        high SPI_DO
SPI_IO_0:
        low SPI_CLK
        X = X * 2 + SPI_DI	' shift X left and add input bit to X
        high SPI_CLK
    next
    return
Visit my blog - http://tronim8.blogspot.com/
 
Last edited:

hippy

Ex-Staff (retired)
Thanks for the code and I'm sure it will be appreciated.

The problem you have could be an intrinsic one with the VMUSIC2 but I'm not familiar with it and don't have one to test with. One question, and I don't know who would have an answer; is it hardware or software SPI in the VMUSIC2 ?

If it is software I'm not sure how you get around it having data to send then stopping until it has been read. It may be a matter of reading the SPI data quickly enough that it doesn't interupt the audio output.

If hardware, speed shouldn't be so important but if there's a byte waiting to be sent it cannot send the next until that's been read so the software could still be blocking. Looking at the code you seem to be reading anything that may be there as quickly as possible, so it could simply be that when there is something it's simply not read quickly enough.

The PICAXE-18X is quite slow doing bit-banged SPI so this could be the main problem.

Adding a "SETFREQ M8" at the start will be a good start, doubling execution speed. There are code optimisations possible which would improve things and you will get better performance from unrolling the loops and in-lining subroutine calls. Get the SPI_IO routine running as fast as possible and everything else will benefit.

The 18X should be configurable to use its on-chip SPI hardware even though there's no direct PICAXE Basic command support for that. That would be a bit fiddly and take some experimenting with but should be doable - Do you have a scope ?

One thing to try ... Once you've issued the play command, don't read any SPI looking for time stamps or end of track just go into an idle loop; does the music play without these interruptions or does it stop after a second ? That may show one way to go forward with decent music quality though you'll have to find a way of determining when the track has ended. It would also give an idea as to what the VMUSIC2 firmware is doing.

In the meantime, this should help get the SPI_IO routine up to full speed ( don't forget to backup what you already have )...

Change the symbols thus -

Symbol X = b0
Symbol SPI_RW = bit8
Symbol SPI_OK = bit9
Symbol SPI_DO = pin7

Change SPI_IO thus -

SPI_IO:
SPI_DO = bit7 : Low SPI_CLK : bit7 = SPI_DI : High SPI_CLK
SPI_DO = bit6 : Low SPI_CLK : bit6 = SPI_DI : High SPI_CLK
SPI_DO = bit5 : Low SPI_CLK : bit5 = SPI_DI : High SPI_CLK
SPI_DO = bit4 : Low SPI_CLK : bit4 = SPI_DI : High SPI_CLK
SPI_DO = bit3 : Low SPI_CLK : bit3 = SPI_DI : High SPI_CLK
SPI_DO = bit2 : Low SPI_CLK : bit2 = SPI_DI : High SPI_CLK
SPI_DO = bit1 : Low SPI_CLK : bit1 = SPI_DI : High SPI_CLK
SPI_DO = bit0 : Low SPI_CLK : bit0 = SPI_DI : High SPI_CLK
Return

Don't forget the "SETFREQ M8" !
 

Phockzie

New Member
Thank you, that's working much better.

I had to make sure that the code reads the SPI port constantly to keep the buffer clear.

If i don't read the SPI port (and clear the buffer) the playback is interrupted.

Code:
SPI_GO:	' Bitbang SPI 
		' Entry - SPI_RW = 1 for Read, 0 for Write
		'         SPI_ADD = 1 for Data, 0 for Register
		'         X = Byte to Write
		' Exit -  SPI_OK = 1 for Failure, 0 for Success
		'         X = Byte read
	high led1
	high SPI_CS
	low SPI_CLK : high SPI_CLK
	SPI_DO = 1 ' SPI Start bit
	low SPI_CLK : high SPI_CLK
	SPI_DO = SPI_RW ' 1 = SPI Read, 0 = SPI Write
	low SPI_CLK : high SPI_CLK
	SPI_DO = SPI_ADD ' SPI ADD (data/REGISTER)
	low SPI_CLK : high SPI_CLK
	SPI_DO = bit7 : low SPI_CLK : bit7 = SPI_DI : high SPI_CLK
	SPI_DO = bit6 : low SPI_CLK : bit6 = SPI_DI : high SPI_CLK
	SPI_DO = bit5 : low SPI_CLK : bit5 = SPI_DI : high SPI_CLK
	SPI_DO = bit4 : low SPI_CLK : bit4 = SPI_DI : high SPI_CLK
	SPI_DO = bit3 : low SPI_CLK : bit3 = SPI_DI : high SPI_CLK
	SPI_DO = bit2 : low SPI_CLK : bit2 = SPI_DI : high SPI_CLK
	SPI_DO = bit1 : low SPI_CLK : bit1 = SPI_DI : high SPI_CLK
	SPI_DO = bit0 : low SPI_CLK : bit0 = SPI_DI : high SPI_CLK
	low SPI_CLK
	SPI_OK = SPI_DI ' Success?
	high SPI_CLK
	low SPI_CS
	SPI_DO = 0
	low led1
	return
 

djmikeys

New Member
Hi,

I'm having problems with making my Vmusic2 module play. I have connected it up in the SPI mode with the following pins connected to the picaxe 18x:

Vmusic2 pin 1 - Ground
Vmusic2 pin 2 - output 7 on picaxe
Vmusic2 pin 3 - 5V
Vmusic2 pin 4 - input 7 on picaxe
Vmusic2 pin 5 - output 6 on picaxe
Vmusic2 pin 6 - output 5 on picaxe
Vmusic2 pin 7 - not connected

I have the jumper bridging from uart/spi to the ground on the Vmusic2 module. My track on the USB stick is named '1.mp3'. I am running the code example above:

Symbol X = B6
Symbol N = B7
Symbol D = B8
Symbol SPI_RW = Bit0 '0 = Write, 1 = Read
Symbol SPI_OK = Bit1 '0 = Success, 1 = Failure
Symbol SPI_Read = 1
Symbol SPI_Write = 0
Symbol SPI_CS = Output5
Symbol SPI_CLK = Output6 ' The VMUSIC clock is active low, not active high as in the manual
Symbol SPI_DO = Output7
Symbol SPI_DI = Input7


MAIN:
Pause 1000
sertxd("Starting",CR,LF) ' Show status via debug terminal
low SPI_CS
gosub SPI_WaitForPrompt ' wait for VMUSIC2 Prompt on the SPI bus (">", CR) after initialisation
sertxd("Disk found",CR,LF) ' Show status via debug terminal
d = $91 ' IPH ' VMUSIC2 Short Command for hex input / output
gosub SPI_SendCmdCR
gosub SPI_EmptyRX ' Empty RX Buffer
d = $10 ' SCS ' VMUSIC2 Short Command for "Short Command Mode"
gosub SPI_SendCmdCR
gosub SPI_EmptyRX

gosub vm2_Playmp3 ' Play a tune

end


vm2_Playmp3:
d = $1D ' VMUSIC2 Short command for Play Music File
gosub SPI_SendCmd
d = $20
gosub SPI_SendCmd
d = "1"
gosub SPI_SendCmd
d = "."
gosub SPI_SendCmd
d = "m"
gosub SPI_SendCmd
d = "p"
gosub SPI_SendCmd
d = "3"
gosub SPI_SendCmd
d = CR
gosub SPI_SendCmd
gosub SPI_EmptyRX
return

SPI_SendCmdCR: ' SPI Send the byte in "D" to the SPI bus then send a "CR" to the bus
gosub SPI_SendCmd
D = CR
gosub SPI_SendCmd
return

SPI_SendCmd: ' SPI Send the byte in "D" until a "Status OK" is seen
SPI_RW = SPI_Write
do
gosub SPI_GO
loop until SPI_OK = 0
return

SPI_EmptyRX: ' Read the SPI buffer until status bit is 1 to clear it
SPI_RW = SPI_Read
do
gosub SPI_GO
loop until SPI_OK = 1
return

SPI_WaitForPrompt: ' subroutine which waits for the prompt from the VMUSIC2 (">", CR)
d = ">"
gosub SPI_WaitForD
d = CR
gosub SPI_WaitForD
return

SPI_WaitForD: ' Keep reading the SPI bus until the character in "D" is seen
SPI_RW = SPI_Read
do
do
gosub SPI_GO
loop until SPI_OK = 0
loop until X = D
return

SPI_GO: ' bitbang the VMUSIC2 SPI bus
' Entry - D = Byte to write to SPI bus, SPI_RW = either SPI_Write or SPI_Read
' Exit = X = Byte Read from SPI bus, SPI_OK = either 0 or 1 depending on success status
if SPI_RW = SPI_Write then
X = D
end if
low SPI_CS
high SPI_CS
high SPI_DO ' SPI Start bit
low SPI_CLK
high SPI_CLK
if SPI_RW = SPI_WRITE then
low SPI_DO ' SPI Read Status Bit
else
high SPI_DO ' SPI Write Status Bit
end if
low SPI_CLK
high SPI_CLK
low SPI_DO ' SPI "ADD" 0 = data 1 = REGISTER
low SPI_CLK
high SPI_CLK
gosub SPI_IO
low SPI_CLK
SPI_OK = SPI_DI ' Success?
high SPI_CLK
low SPI_CS
low SPI_DO
return

SPI_IO: ' 8 bit bitbang routine
for N = 0 to 7
if X > 127 Then SPI_IO_1
low SPI_DO
goto SPI_IO_0
SPI_IO_1:
high SPI_DO
SPI_IO_0:
low SPI_CLK
X = X * 2 + SPI_DI ' shift X left and add input bit to X
high SPI_CLK
next
return
----------------------------------------

The program downloads fine, and the Vmusic2 module seems to turn on as the red LED turns on and the usb stick flashes but the track does not play. Has anyone got any ideas, am I missing anything out?

Or does anyone have sample code for running the Vmusic2 in UART mode?
 
Last edited:
Top