There's a hidden trick in there: When you pass a Hub variable or xDATA symbol to a subroutine or function it is passed by address, not by value. In order to read from the hub you have to use RDxxxx, in this case we use RDBYTE as the sequence is a table of bytes. The syntax for RDBYTE is RDBYTE hubaddress, value. This gets used six times (for your six RGB led groups) in PLAY checking for an end-of-sequence value ($FF) each time, and then incrementing (adding one to) the address for the next group. After all the LEDs are updated the delay value you passed is used with DELAY_MS (shell for PAUSE).
There is a compiler trick in use, as well. You see, PropBASIC knows how to adjust outputs for a pin group, based on the location of that pin group. The [noparse][[/noparse]internal] code isn't difficult, nor is it trivial. For example, if you want to do this:
CSG6 = PURPLE
... the compiler actually generates the following code. I've added comments to explain what each line does
' CS6 = PURPLEmov __temp1,#PURPLE ' copy PURPLE (%101) to __temp1shl __temp1,#15' align with base pin of CS6 groupand __temp1,CS6 ' clear non-CS6 bits from __temp1andnouta,CS6 ' clear old CS6 group outputsorouta,__temp1 ' write new value to CS6 group outputs
Geekgirl, · Yeah if you're coming from PBASIC "pin groups" are great. · If you need more assistance please ask. It's nice to see what forum members are "up to" with PropBASIC.
· P.S. Jon must have downloaded my code before I fixed the color names.· ORANGE should be YELLOW, and PURPLE should be MAGENTA, and AQUA should be CYAN.
A little more development on using Bean's method to talk to Spin objects from PropBASIC, running on Rayman's PSM.
The following makes two Spin objects available on demand to the main BASIC program;
This time there actually is some code in the BASIC program; which generates a tone, then displays version detail on the LCD.
The object of posting this is so that newcomers like myself can have an easy example, with a low level of abstraction.
T o n y
DEVICE P8X32A, XTAL1, PLL16X
FREQ 80_000_000
tonegenStart CON1
psmStart CON2
psmDeviceinfo CON3
spinCmd HUB BYTE = 0
hub_long1 HUB LONG
hub_long2 HUB LONG
hub_long3 HUB LONG
temp VARLONG
ASM
OBJ
soundmachine: "psm_tonegenerator"
psmmachine: "psm_serialcontrol_a"PUBSpinStartCogInit(1, @__Init, @__DATASTART)
Repeatcase spinCmd
tonegenStart:
soundmachine.tonegen(hub_long1,hub_long2,hub_long3)
spinCmd := 0
psmStart:
psmmachine.main
spinCmd := 0
psmDeviceinfo:
psmmachine.showdeviceinfo
spinCmd := 0
ENDASM
PROGRAM Start
Start:
'start tonegen driver WRLONG hub_long1, 400WRLONG hub_long2, 500WRLONG hub_long3, 3WRBYTE spinCmd, tonegenStart
'wait for driver to process
DO
RDBYTE spinCmd, temp
LOOP UNTIL temp = 0'start psm driver WRBYTE spinCmd, psmStart
'wait for driver to process
DO
RDBYTE spinCmd, temp
LOOP UNTIL temp = 0'start deviceinfo driver WRBYTE spinCmd, psmDeviceinfo
'wait for driver to process
DO
RDBYTE spinCmd, temp
LOOP UNTIL temp = 0
END
Post Edited By Moderator (Bean (Hitt Consulting)) : 1/1/2010 12:55:35 AM GMT
Here's another demo using the tone generator. Note that the psm_tonegenerator object hard-codes the output pins so you may need to change this (as I did) if you're using the Propeller Demo Board (I may *liberate* this code to create my own version that can pass pins and be stopped while playing).
This demo plays three tones and then goes into a random loop -- somewhat reminiscent of old sci-fi computer sounds.
JonnyMac,
Thanks for the wonderful tonegenerator example!
It's running in the background, playing music while I'm studying the code.
It's 0130 here, back to some nightwork after the party.
T o n y
You need to be careful with duration -- if it goes more than 25 or so then you could get a rollover problem (from positive to negative) with the values. Since the *typical* clkfreq setting of a Propeller project is 80MHz and you have a constant value of 1000 you could boil the division down to 80_000, like this:
The duration is passed in __param1 and we don't need to use RETURN (just consumes a line of precious code space) because functions use __paramx variables to send values back to the caller.
PropBASIC/FUNC question
/Continued
(Project is to attempt re-write of Rayman's PSM_ToneGenerator in PropBASIC)
I've tried to work in the FUNC calls; the following gets past the compiler - which is encouraging.
I'm uncertain whether I've used the __paramx variables correctly to get information in and out of the FUNC.
My progress certainly improved when my blurry eyesight spotted the 'double-underscore' typography!
Thank you, T o n y
DEVICE P8X32A, XTAL1, PLL16X
XIN 5_000_000
ToneNumberSteps VARLONG
ToneLeftPhaseStep VARLONG
ToneRightPhaseStep VARLONG
ToneLeftAttenuation VARLONG
ToneRightAttenuation VARLONG
ToneLeftPin VARLONG
ToneRightPin VARLONG
ToneRunning VARLONG
Frequency VARLONG
Duration VARLONG
Attenuation VARLONG
LeftFrequency VARLONG
RightFrequency VARLONG
Tonegen SUB3,5
GetToneNumberSteps FUNC 1
GetTonePhaseStep FUNC 1
PROGRAM Start
Start:
DO
Tonegen(400,500,3) 'outputs test-tone of 400Hz, 500mS, attenuation level 3
PAUSE 3000
LOOP
END
FUNC GetToneNumberSteps
' use duration as __param1
__param2 = clkfreq / 200_000
__param1 = __param1 * __param2
'return of __param1 requiredRETURN __param1
ENDFUNC
FUNC GetTonePhaseStep
' use Frequency as __param1
__param2 = 1 << 15
__param1 = __param1 * __param2
__param2 = clkfreq / 200
__param1 = __param1 / __param2
__param2 = 1 << 13
__param1 = __param1 * __param2
__param2 = 1 << 4
__param1 / __param1 * __param2
'return of _param1 required RETURN __param1
ENDFUNC
SUB Tonegen (frequency,duration,attenuation)¦LeftFrequency,RightFrequency)
ToneLeftPin=5
ToneRightPin=4
LeftFrequency=Frequency
RightFrequency=Frequency
ToneNumberSteps=GetToneNumberSteps Duration
ToneLeftPhaseStep=GetTonePhaseStep LeftFrequency
ToneRightPhaseStep=GetTonePhaseStep RightFrequency
ToneLeftAttenuation=Attenuation
ToneRightAttenuation=Attenuation
ToneRunning=true'COGSTART ......assembly stuff to come here with DAT etc to follow
ENDSUB
Out of curiosity, what's the rationale behind using cogstart instead of cognew and swapping the parameters for RDxxx/WRxxx (compared to their PASM equivalents)? Regarding the latter, not that I mind that much but people starting with BASIC and going for PASM later might find this confusing.
The idea behind PropBASIC is to help those coming from PBASIC make the transition, hence the RDxxxx and WRxxxx more closely match READ and WRITE from PBASIC (and SX/B) where the address is the first parameter. Mind you, that's a guess on my part -- I do docs, but didn't design the compiler.
JonnyMac said...
The idea behind PropBASIC is to help those coming from PBASIC make the transition, hence the RDxxxx and WRxxxx more closely match READ and WRITE from PBASIC (and SX/B) where the address is the first parameter.
Fair enough, not having used PBASIC I didn't/couldn't make that connection but that sounds reasonable [noparse]:)[/noparse]
PropBasic is compiled to PASM. I remember somebody did work on how to call SPIN from PASM.
But I think you have to fiddle around with pointers each time you change a single byte in the SPIN-files.
So it will be much easier to learn SPIN than learning how startadresses of spin-methods were changed by the SPIN-bytecode-compiler
kuroneko said...
Out of curiosity, what's the rationale behind using cogstart instead of cognew and swapping the parameters for RDxxx/WRxxx (compared to their PASM equivalents)? Regarding the latter, not that I mind that much but people starting with BASIC and going for PASM later might find this confusing.
Well, COGSTART started life as TASKSTART, but was changed because it really is starting a COG with a specific task.
RDxxxx and WRxxxx allow multiple values to be read or written with one command. This would have been a strange syntax if the address wasn't first. Plus it is a more consistant syntax.
Bean.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Use BASIC on the Propeller with the speed of assembly language.
I've spent the day trying to work out how to run some Assembler within PropBASIC, in my continuing efforts to translate Rayman's fabulous PSM_ToneGenerator into PropBASIC.
My thinking is that once I can do this for a single driver, then I should have learned enough to attempt one or two of the others; thus enabling easy use of Rayman's PSM to PropBASIC users.
Appended below is my current test-stub.
It fails gloriously where I try and pass a VAR from PropBASIC into the cog, using a Spin command within the ASM-ENDASM;
I have studied the different COG commands within Spin, PASM and PropBASIC and am none the wiser.
You will see that I have not even called the SUB Tonegen; just including the asterisked line kills everything!
It seems unlikely that I will stumble on the solution without some help from my friends ...
DEVICE P8X32A, XTAL1, PLL16X
XIN 5_000_000
ToneNumberSteps VARLONG
ToneLeftPhaseStep VARLONG
ToneRightPhaseStep VARLONG
ToneLeftAttenuation VARLONG
ToneRightAttenuation VARLONG
ToneLeftPin VARLONG
ToneRightPin VARLONG
ToneRunning VARLONG
Frequency VARLONG
Duration VARLONG
Attenuation VARLONG
LeftFrequency VARLONG
RightFrequency VARLONG
Tonegen SUB3,5
GetToneNumberSteps FUNC 1
GetTonePhaseStep FUNC 1
PROGRAM Start 'blinks LED as minimal healthcheck!
Start:
LED PIN 0 LOW
DO
HIGH LED
PAUSE 1000
TOGGLE LED
PAUSE 1000
LOOP
END
FUNC GetToneNumberSteps
' use duration as __param1'lots more code hereRETURN __param1
ENDFUNC
FUNC GetTonePhaseStep
' use Frequency as __param1 'lots more code here RETURN __param1
ENDFUNC
SUB Tonegen (frequency,duration,attenuation)¦LeftFrequency,RightFrequency)
ToneNumberSteps=GetToneNumberSteps Duration
ToneLeftPhaseStep=GetTonePhaseStep LeftFrequency
ToneRightPhaseStep=GetTonePhaseStep RightFrequency
ToneRunning=1
ASM
pubspinstartcognew(@ToneStart,@ToneNumberSteps) '******************************************* org0
ToneStart 'Beginning of assembly tone generator'lots of assembly code here
ENDASM
ENDSUB
@Bean
Thanks for all the advice!
I am delving deeply into Spin, PropBASIC and PASM. Of course I'm completely out of my depth but have not yet
given up hope of translating Rayman's Spin/PASM sound-driver into PropBASIC.
Here's the latest code. I have taken your advice and have started a TASK for the ASM.
I need to pass the 7 input parameters from the PropBASIC cog into the TASK cog, using the address TonenumberSteps.
These seven then become appropriately equivalent RES's declared within the TASK cog.
After much research, I am clearer about some of the memory issues; but no clearer on how to correct the code.
However, it does get past the compiler and blink the two indicator LED's, which for me is progress.
There is a great chunk of Rayman's self-contained ASM code to go back in; but I have reduced it to this stub in order
to resolve the VAR/res issue first.
Thank you, T o n y
DEVICE P8X32A, XTAL1, PLL16X
XIN 5_000_000'following 7 variables declared and used by first cog; trying to pass these to TASK cog ***
ToneNumberSteps VARLONG
ToneLeftPhaseStep VARLONG
ToneRightPhaseStep VARLONG
ToneLeftAttenuation VARLONG
ToneRightAttenuation VARLONG
ToneLeftPin VARLONG
ToneRightPin VARLONG'other variables
ToneRunning VARLONG'set to 1 in Tonegen SUB; would like to set to 0 on exiting TASK ***
Frequency VARLONG
Duration VARLONG
Attenuation VARLONG
LeftFrequency VARLONG
RightFrequency VARLONG'SUB, FUNCs and TASK
Tonegen SUB3,5
GetToneNumberSteps FUNC 1
GetTonePhaseStep FUNC 1
TonegenAssembly TASK
PROGRAM Start
Start:
LED PIN 0 LOW 'prepares PropBASIC program indicator LED
DO
TOGGLE LED 'blinks PropBASIC LED as minimal healthcheck
PAUSE 1000'aids debug by slowing things down
Tonegen 400,500,3'will eventually output test tone 400Hz, 500mS, attenuation level 3
LOOP
END
FUNC GetToneNumberSteps
' use duration as __param1' converts the following Spin into PropBASIC: ToneNumberSteps:=(duration*(clkfreq/1000))/200)
__param2 = clkfreq / 200_000
__param1 = __param1 * __param2
'return of __param1 requiredRETURN __param1 'haven't yet managed to get rid of this line
ENDFUNC
FUNC GetTonePhaseStep
' use Left or Right Frequency passed as __param1 ' converts the following Spin into PropBASIC: TonePhaseStep:=(L or R Frequency*(1<<15)/(clkfreq/200))*(1<<13)*(1<<4)
__param2 = 1 << 15
__param1 = __param1 * __param2
__param2 = clkfreq / 200
__param1 = __param1 / __param2
__param2 = 1 << 13
__param1 = __param1 * __param2
__param2 = 1 << 4
__param1 / __param1 * __param2
'return of _param1 required RETURN __param1 'haven't yet managed to get rid of this line
ENDFUNC
SUB Tonegen (frequency,duration,attenuation)¦LeftFrequency,RightFrequency)
LED2 PIN 1 LOW 'prepares sub-routine indicator LED
ToneLeftPin=11
ToneRightPin=10
LeftFrequency=Frequency
RightFrequency=Frequency
ToneNumberSteps=GetToneNumberSteps Duration '***ToneNumberSteps is value I would like to pass to TASK
ToneLeftPhaseStep=GetTonePhaseStep LeftFrequency
ToneRightPhaseStep=GetTonePhaseStep RightFrequency
ToneLeftAttenuation=Attenuation
ToneRightAttenuation=Attenuation
ToneRunning=1
COGSTART ToneGenAssembly
TOGGLE LED2
PAUSE 1000
ENDSUB
TASK TonegenAssembly
ASM
DAT'Assembly Tone Generatororg0
Tonestart '***beginning of assembly tone generator '***load input parameters from first cog to par in'***TASK cog, given address ToneNumberSteps from '***first cog; passed to par in TASK cog.movd [img]http://forums.parallax.com/images/smilies/tongue.gif[/img]ar,#tNumberSteps 'copies 7 parameters to location starting with tNumberSteps mov temp1,parmov temp2,#7'there are 7 input parameters
[img]http://forums.parallax.com/images/smilies/tongue.gif[/img]ar rdlong0,temp1
add [img]http://forums.parallax.com/images/smilies/tongue.gif[/img]ar,dlsb
add temp1,#4djnz temp2,#[img]http://forums.parallax.com/images/smilies/tongue.gif[/img]ar
'loads more code here'now closing code'would like to set ToneRunning in first cog to 0 here! ***COGID temp1
COGSTOP temp1
'setup parameters
tCounterMode long%00011000_00000000_00000000_00000000
dlsb long1 << 9'phase accumulators
LeftPhase long0
RightPhase long0'main loop vars
dcnt long200'#clocks/main loop --> gives 400kHz update rate
offset long$8000_0000'Working variables
temp1 res1
temp2 res1
wait res1'Input Parameters
tNumberSteps res1'Determines tone duration (left and right)
tLeftStep res1'Determines left tone frequency
tRightStep res1'Determines right tone frequency
tLeftAtten res1'Determines left tone volume (0=loud, 8=soft)
tRightAtten res1'Determines right tone volume (0=loud, 8=soft)
tLeftPin res1'Pin# for left audio output (negative number disables)
tRightPin res1'Pin# for right audio output (negative number disables)
ENDASM
ENDTASK
I'd have replied more quickly, but everything's come to a halt with just 1/2" of snow!
(abandoned car last night; walked home; got it back at the midnight thaw; took 2 hours travelling 4 miles by train this morning)
Rayman's sound-driver is PSM_ToneGenerator.spin from the PSM section of his Rayslogic website:
Comments
There is a compiler trick in use, as well. You see, PropBASIC knows how to adjust outputs for a pin group, based on the location of that pin group. The [noparse][[/noparse]internal] code isn't difficult, nor is it trivial. For example, if you want to do this:
CSG6 = PURPLE
... the compiler actually generates the following code. I've added comments to explain what each line does
' CS6 = PURPLE mov __temp1,#PURPLE ' copy PURPLE (%101) to __temp1 shl __temp1,#15 ' align with base pin of CS6 group and __temp1,CS6 ' clear non-CS6 bits from __temp1 andn outa,CS6 ' clear old CS6 group outputs or outa,__temp1 ' write new value to CS6 group outputs
Post Edited (JonnyMac) : 1/1/2010 2:36:52 AM GMT
· Yeah if you're coming from PBASIC "pin groups" are great.
· If you need more assistance please ask. It's nice to see what forum members are "up to" with PropBASIC.
· P.S. Jon must have downloaded my code before I fixed the color names.· ORANGE should be YELLOW, and PURPLE should be MAGENTA, and AQUA should be CYAN.
Bean.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Try BASIC on the Propeller.
PropBASIC thread http://forums.parallax.com/showthread.php?p=867134
Post Edited (Bean (Hitt Consulting)) : 12/31/2009 9:54:16 PM GMT
The following makes two Spin objects available on demand to the main BASIC program;
This time there actually is some code in the BASIC program; which generates a tone, then displays version detail on the LCD.
The object of posting this is so that newcomers like myself can have an easy example, with a low level of abstraction.
T o n y
DEVICE P8X32A, XTAL1, PLL16X FREQ 80_000_000 tonegenStart CON 1 psmStart CON 2 psmDeviceinfo CON 3 spinCmd HUB BYTE = 0 hub_long1 HUB LONG hub_long2 HUB LONG hub_long3 HUB LONG temp VAR LONG ASM OBJ soundmachine: "psm_tonegenerator" psmmachine: "psm_serialcontrol_a" PUB SpinStart CogInit(1, @__Init, @__DATASTART) Repeat case spinCmd tonegenStart: soundmachine.tonegen(hub_long1,hub_long2,hub_long3) spinCmd := 0 psmStart: psmmachine.main spinCmd := 0 psmDeviceinfo: psmmachine.showdeviceinfo spinCmd := 0 ENDASM PROGRAM Start Start: 'start tonegen driver WRLONG hub_long1, 400 WRLONG hub_long2, 500 WRLONG hub_long3, 3 WRBYTE spinCmd, tonegenStart 'wait for driver to process DO RDBYTE spinCmd, temp LOOP UNTIL temp = 0 'start psm driver WRBYTE spinCmd, psmStart 'wait for driver to process DO RDBYTE spinCmd, temp LOOP UNTIL temp = 0 'start deviceinfo driver WRBYTE spinCmd, psmDeviceinfo 'wait for driver to process DO RDBYTE spinCmd, temp LOOP UNTIL temp = 0 END
Post Edited By Moderator (Bean (Hitt Consulting)) : 1/1/2010 12:55:35 AM GMT
· If you put your code inside the "Formatted Code" area (the # icon), it will keep the spacing.
·
Bean
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Try BASIC on the Propeller.
PropBASIC thread http://forums.parallax.com/showthread.php?p=867134·
This demo plays three tones and then goes into a random loop -- somewhat reminiscent of old sci-fi computer sounds.
Post Edited (JonnyMac) : 1/1/2010 1:18:15 AM GMT
Thanks for the wonderful tonegenerator example!
It's running in the background, playing music while I'm studying the code.
It's 0130 here, back to some nightwork after the party.
T o n y
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
JMH
Along with a couple of bug fixes, PropBASIC now supports inline strings.
Inline strings can be used anywhere a DATA label can be used.
NOTE: Inline strings are Z-strings, so the compiler will automatically add a zero·to the end of them as a "end of string" indicator byte.
Here is a demo showing inline strings:
DEVICE P8X32A, XTAL1, PLL16X FREQ 80_000_000 Baud CON "T115200" TX PIN 30 HIGH temp VAR Long SendChar SUB 1 SendStr SUB 1 Message DATA "GoodBye", 0 PROGRAM Start Start: GETADDR "Testing 1,2,3", temp SendStr temp PAUSE 1000 SendStr "Hello" PAUSE 1000 SendStr Message PAUSE 1000 GOTO Start END SUB SendChar SEROUT TX, Baud, __param1 ENDSUB SUB SendStr __param2 = __param1 ' SendChar uses __param1 DO RDBYTE __param2, __param3 IF __param3 = 0 THEN EXIT SendChar __param3 INC __param2 LOOP SendChar 13 ENDSUB
Bean.
·
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Use BASIC on the Propeller with the speed of assembly language.
PropBASIC thread http://forums.parallax.com/showthread.php?p=867134
Post Edited (Bean (Hitt Consulting)) : 1/2/2010 3:25:57 PM GMT
The bug has been fixed in version 00.00.54 in the first post in this thread.
Bean
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Use BASIC on the Propeller with the speed of assembly language.
PropBASIC thread http://forums.parallax.com/showthread.php?p=867134·
I have fixed it and posted version 00.00.55 in the first post.
Bean.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Use BASIC on the Propeller with the speed of assembly language.
PropBASIC thread http://forums.parallax.com/showthread.php?p=867134·
Hi all,
May I tempt you with the following easy question?
The following compiles nicely; but how do I do the three steps in one?
FUNC GetToneNumberSteps Temp1=Duration*clkfreq Temp1=Temp1/1000 ToneNumberSteps=Temp1/200 RETURN ToneNumberSteps ENDFUNC
· ToneNumberSteps·= Duration * clkfreq
· ToneNumberSteps = ToneNumberSteps / 200_000
RETURN ToneNumberSteps
Bean
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Use BASIC on the Propeller with the speed of assembly language.
PropBASIC thread http://forums.parallax.com/showthread.php?p=867134·
You need to be careful with duration -- if it goes more than 25 or so then you could get a rollover problem (from positive to negative) with the values. Since the *typical* clkfreq setting of a Propeller project is 80MHz and you have a constant value of 1000 you could boil the division down to 80_000, like this:
FUNC GetToneNumberSteps __param1 = __param1 * 80_000 __param1 = __param1 / 200 ENDFUNC
The duration is passed in __param1 and we don't need to use RETURN (just consumes a line of precious code space) because functions use __paramx variables to send values back to the caller.
FUNC GetToneNumberSteps __param1 = __param1 * 400 ENDFUNC
If you need to accommodate clkfreq I think you can simplify to:
FUNC GetToneNumberSteps __param2 = clkfreq / 200_000 __param1 = __param1 * __param2 ENDFUNC
Post Edited (JonnyMac) : 1/3/2010 9:28:31 PM GMT
Now to improve my code ...
/Continued
(Project is to attempt re-write of Rayman's PSM_ToneGenerator in PropBASIC)
I've tried to work in the FUNC calls; the following gets past the compiler - which is encouraging.
I'm uncertain whether I've used the __paramx variables correctly to get information in and out of the FUNC.
My progress certainly improved when my blurry eyesight spotted the 'double-underscore' typography!
Thank you, T o n y
DEVICE P8X32A, XTAL1, PLL16X XIN 5_000_000 ToneNumberSteps VAR LONG ToneLeftPhaseStep VAR LONG ToneRightPhaseStep VAR LONG ToneLeftAttenuation VAR LONG ToneRightAttenuation VAR LONG ToneLeftPin VAR LONG ToneRightPin VAR LONG ToneRunning VAR LONG Frequency VAR LONG Duration VAR LONG Attenuation VAR LONG LeftFrequency VAR LONG RightFrequency VAR LONG Tonegen SUB 3,5 GetToneNumberSteps FUNC 1 GetTonePhaseStep FUNC 1 PROGRAM Start Start: DO Tonegen(400,500,3) 'outputs test-tone of 400Hz, 500mS, attenuation level 3 PAUSE 3000 LOOP END FUNC GetToneNumberSteps ' use duration as __param1 __param2 = clkfreq / 200_000 __param1 = __param1 * __param2 'return of __param1 required RETURN __param1 ENDFUNC FUNC GetTonePhaseStep ' use Frequency as __param1 __param2 = 1 << 15 __param1 = __param1 * __param2 __param2 = clkfreq / 200 __param1 = __param1 / __param2 __param2 = 1 << 13 __param1 = __param1 * __param2 __param2 = 1 << 4 __param1 / __param1 * __param2 'return of _param1 required RETURN __param1 ENDFUNC SUB Tonegen (frequency,duration,attenuation)¦LeftFrequency,RightFrequency) ToneLeftPin=5 ToneRightPin=4 LeftFrequency=Frequency RightFrequency=Frequency ToneNumberSteps=GetToneNumberSteps Duration ToneLeftPhaseStep=GetTonePhaseStep LeftFrequency ToneRightPhaseStep=GetTonePhaseStep RightFrequency ToneLeftAttenuation=Attenuation ToneRightAttenuation=Attenuation ToneRunning=true 'COGSTART ......assembly stuff to come here with DAT etc to follow ENDSUB
PropBasic is compiled to PASM. I remember somebody did work on how to call SPIN from PASM.
But I think you have to fiddle around with pointers each time you change a single byte in the SPIN-files.
So it will be much easier to learn SPIN than learning how startadresses of spin-methods were changed by the SPIN-bytecode-compiler
best regards
Stefan
RDxxxx and WRxxxx allow multiple values to be read or written with one command. This would have been a strange syntax if the address wasn't first. Plus it is a more consistant syntax.
Bean.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Use BASIC on the Propeller with the speed of assembly language.
PropBASIC thread http://forums.parallax.com/showthread.php?p=867134·
Hi experts,
I've spent the day trying to work out how to run some Assembler within PropBASIC, in my continuing efforts to translate Rayman's fabulous PSM_ToneGenerator into PropBASIC.
My thinking is that once I can do this for a single driver, then I should have learned enough to attempt one or two of the others; thus enabling easy use of Rayman's PSM to PropBASIC users.
Appended below is my current test-stub.
It fails gloriously where I try and pass a VAR from PropBASIC into the cog, using a Spin command within the ASM-ENDASM;
I have studied the different COG commands within Spin, PASM and PropBASIC and am none the wiser.
You will see that I have not even called the SUB Tonegen; just including the asterisked line kills everything!
It seems unlikely that I will stumble on the solution without some help from my friends ...
DEVICE P8X32A, XTAL1, PLL16X XIN 5_000_000 ToneNumberSteps VAR LONG ToneLeftPhaseStep VAR LONG ToneRightPhaseStep VAR LONG ToneLeftAttenuation VAR LONG ToneRightAttenuation VAR LONG ToneLeftPin VAR LONG ToneRightPin VAR LONG ToneRunning VAR LONG Frequency VAR LONG Duration VAR LONG Attenuation VAR LONG LeftFrequency VAR LONG RightFrequency VAR LONG Tonegen SUB 3,5 GetToneNumberSteps FUNC 1 GetTonePhaseStep FUNC 1 PROGRAM Start 'blinks LED as minimal healthcheck! Start: LED PIN 0 LOW DO HIGH LED PAUSE 1000 TOGGLE LED PAUSE 1000 LOOP END FUNC GetToneNumberSteps ' use duration as __param1 'lots more code here RETURN __param1 ENDFUNC FUNC GetTonePhaseStep ' use Frequency as __param1 'lots more code here RETURN __param1 ENDFUNC SUB Tonegen (frequency,duration,attenuation)¦LeftFrequency,RightFrequency) ToneNumberSteps=GetToneNumberSteps Duration ToneLeftPhaseStep=GetTonePhaseStep LeftFrequency ToneRightPhaseStep=GetTonePhaseStep RightFrequency ToneRunning=1 ASM pub spinstart cognew(@ToneStart,@ToneNumberSteps) '******************************************* org 0 ToneStart 'Beginning of assembly tone generator 'lots of assembly code here ENDASM ENDSUB
Post Edited (TonyWaite) : 1/4/2010 7:31:31 PM GMT
I'm not quite following what you are trying to do ???
Do you want the tone generator to run in a seperate cog ? If so, then use a TASK.
If not, then just put
ASM
' Your assembly instructions
ENDASM
It looks like you're making it harder than it is.
Bean
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Use BASIC on the Propeller with the speed of assembly language.
PropBASIC thread http://forums.parallax.com/showthread.php?p=867134·
@Bean
Thanks for all the advice!
I am delving deeply into Spin, PropBASIC and PASM. Of course I'm completely out of my depth but have not yet
given up hope of translating Rayman's Spin/PASM sound-driver into PropBASIC.
Here's the latest code. I have taken your advice and have started a TASK for the ASM.
I need to pass the 7 input parameters from the PropBASIC cog into the TASK cog, using the address TonenumberSteps.
These seven then become appropriately equivalent RES's declared within the TASK cog.
After much research, I am clearer about some of the memory issues; but no clearer on how to correct the code.
However, it does get past the compiler and blink the two indicator LED's, which for me is progress.
There is a great chunk of Rayman's self-contained ASM code to go back in; but I have reduced it to this stub in order
to resolve the VAR/res issue first.
Thank you, T o n y
DEVICE P8X32A, XTAL1, PLL16X XIN 5_000_000 'following 7 variables declared and used by first cog; trying to pass these to TASK cog *** ToneNumberSteps VAR LONG ToneLeftPhaseStep VAR LONG ToneRightPhaseStep VAR LONG ToneLeftAttenuation VAR LONG ToneRightAttenuation VAR LONG ToneLeftPin VAR LONG ToneRightPin VAR LONG 'other variables ToneRunning VAR LONG 'set to 1 in Tonegen SUB; would like to set to 0 on exiting TASK *** Frequency VAR LONG Duration VAR LONG Attenuation VAR LONG LeftFrequency VAR LONG RightFrequency VAR LONG 'SUB, FUNCs and TASK Tonegen SUB 3,5 GetToneNumberSteps FUNC 1 GetTonePhaseStep FUNC 1 TonegenAssembly TASK PROGRAM Start Start: LED PIN 0 LOW 'prepares PropBASIC program indicator LED DO TOGGLE LED 'blinks PropBASIC LED as minimal healthcheck PAUSE 1000 'aids debug by slowing things down Tonegen 400,500,3 'will eventually output test tone 400Hz, 500mS, attenuation level 3 LOOP END FUNC GetToneNumberSteps ' use duration as __param1 ' converts the following Spin into PropBASIC: ToneNumberSteps:=(duration*(clkfreq/1000))/200) __param2 = clkfreq / 200_000 __param1 = __param1 * __param2 'return of __param1 required RETURN __param1 'haven't yet managed to get rid of this line ENDFUNC FUNC GetTonePhaseStep ' use Left or Right Frequency passed as __param1 ' converts the following Spin into PropBASIC: TonePhaseStep:=(L or R Frequency*(1<<15)/(clkfreq/200))*(1<<13)*(1<<4) __param2 = 1 << 15 __param1 = __param1 * __param2 __param2 = clkfreq / 200 __param1 = __param1 / __param2 __param2 = 1 << 13 __param1 = __param1 * __param2 __param2 = 1 << 4 __param1 / __param1 * __param2 'return of _param1 required RETURN __param1 'haven't yet managed to get rid of this line ENDFUNC SUB Tonegen (frequency,duration,attenuation)¦LeftFrequency,RightFrequency) LED2 PIN 1 LOW 'prepares sub-routine indicator LED ToneLeftPin=11 ToneRightPin=10 LeftFrequency=Frequency RightFrequency=Frequency ToneNumberSteps=GetToneNumberSteps Duration '***ToneNumberSteps is value I would like to pass to TASK ToneLeftPhaseStep=GetTonePhaseStep LeftFrequency ToneRightPhaseStep=GetTonePhaseStep RightFrequency ToneLeftAttenuation=Attenuation ToneRightAttenuation=Attenuation ToneRunning=1 COGSTART ToneGenAssembly TOGGLE LED2 PAUSE 1000 ENDSUB TASK TonegenAssembly ASM DAT 'Assembly Tone Generator org 0 Tonestart '***beginning of assembly tone generator '***load input parameters from first cog to par in '***TASK cog, given address ToneNumberSteps from '***first cog; passed to par in TASK cog. movd [img]http://forums.parallax.com/images/smilies/tongue.gif[/img]ar,#tNumberSteps 'copies 7 parameters to location starting with tNumberSteps mov temp1,par mov temp2,#7 'there are 7 input parameters [img]http://forums.parallax.com/images/smilies/tongue.gif[/img]ar rdlong 0,temp1 add [img]http://forums.parallax.com/images/smilies/tongue.gif[/img]ar,dlsb add temp1,#4 djnz temp2,#[img]http://forums.parallax.com/images/smilies/tongue.gif[/img]ar 'loads more code here 'now closing code 'would like to set ToneRunning in first cog to 0 here! *** COGID temp1 COGSTOP temp1 'setup parameters tCounterMode long %00011000_00000000_00000000_00000000 dlsb long 1 << 9 'phase accumulators LeftPhase long 0 RightPhase long 0 'main loop vars dcnt long 200 '#clocks/main loop --> gives 400kHz update rate offset long $8000_0000 'Working variables temp1 res 1 temp2 res 1 wait res 1 'Input Parameters tNumberSteps res 1 'Determines tone duration (left and right) tLeftStep res 1 'Determines left tone frequency tRightStep res 1 'Determines right tone frequency tLeftAtten res 1 'Determines left tone volume (0=loud, 8=soft) tRightAtten res 1 'Determines right tone volume (0=loud, 8=soft) tLeftPin res 1 'Pin# for left audio output (negative number disables) tRightPin res 1 'Pin# for right audio output (negative number disables) ENDASM ENDTASK
· Could you provide a link to Rayman's code ?
· I did a search but I couldn't find it.
Bean
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Use BASIC on the Propeller with the speed of assembly language.
PropBASIC thread http://forums.parallax.com/showthread.php?p=867134
Post Edited (Bean (Hitt Consulting)) : 1/5/2010 9:56:17 PM GMT
I'd have replied more quickly, but everything's come to a halt with just 1/2" of snow!
(abandoned car last night; walked home; got it back at the midnight thaw; took 2 hours travelling 4 miles by train this morning)
Rayman's sound-driver is PSM_ToneGenerator.spin from the PSM section of his Rayslogic website:
http://rayslogic.com/Propeller/Products/PSM/Software/PSM_SerialControl - Archive [noparse][[/noparse]Date 2009.06.26 Time 16.54].zip
And I have uploaded it with this post.
Thanks,
T o n y
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
http://www.propgfx.co.uk/forum/·home of the PropGFX Lite
·
Please download the latest version if you are using PropBASIC.
Tony,
· Here is my version of Raymans tone generator.
Bean.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Use BASIC on the Propeller with the speed of assembly language.
PropBASIC thread http://forums.parallax.com/showthread.php?p=867134
Post Edited (Bean (Hitt Consulting)) : 1/7/2010 1:13:50 AM GMT
Thanks for the brilliant code: I'm studying it to learn how it works.
I had to declare _Freq as VAR LONG to get it to run.
The demonstration loop is very sci fi!
In awe,
T o n y