PASM beginner questions
Hi all
I have been looking at someone's demo programs to blink an LED in PASM. There are a couple of things that I could do with some help on. My verbose comments on the program show them, one is the use of OR instead of MOV in two places (MOV does work there too) and some sort of indirect addressing that I don't grasp yet.
(CODE DELETED)
Any clues will be welcome.
Thanks
Richard
I have been looking at someone's demo programs to blink an LED in PASM. There are a couple of things that I could do with some help on. My verbose comments on the program show them, one is the use of OR instead of MOV in two places (MOV does work there too) and some sort of indirect addressing that I don't grasp yet.
(CODE DELETED)
Any clues will be welcome.
Thanks
Richard

Comments
By indirect addressing perhaps you mean the accessing of HUB RAM with RDLONG? Or perhaps the use of the # in the JMP instruction? I can't really guess.
It was this code that was (perhaps) indirect addressing:
add t1, #4 ' point to "on" ticks
rdlong ontix, t1 ' read on timing
Not sure how that work.
Regards
Richard
Cheers
Richard
I prefer to be clear and not just say "variable" - here we are talking about the address of the variable blinkpin (in hub RAM) being passed to the cog via the PAR register. Sometimes people talk about a variable meaning the address, sometimes the current value, and sometimes as an abstract thing which can be changed (which under the hood always means the address is being used to do the updating and reading).
In case its not clear to a newcomer the cog runs in its own separate RAM (which is 32-bit wide) which cannot be accessed from outside the cog. Each cog can access the hub ram (which is byte-addressed) via rdbyte/rdword/rdlong/wrbyte/wrword/wrlong instructions.
The cog RAM itself contains the instructions of the cog as well as the data, and allows self-modifying code as a result. cog RAM addresses increase by 1 for each long, unlike hub RAM which is byte-addressed.
The PAR register gets passed only 14 bits from the COGNEW instruction, being bits 2 to 15 (enough to address cog RAM on long-word boundaries).
For example: "PAR is pin number passed by COGNEW"
Nope. PAR holds the hub address of the pin number and is passed to the cog. This gets copied into t1 (which can be modified, PAR is read-only) for use with the rdlong instruction which READS a LONG from an address in the hub.
I won't bother detailing all the other errors in your comments but will ask that you sift back through so as not to undo your intention of helping other newcomers. You can in fact edit your own posts to correct mistakes or make clarifications (I do this all the time).
I know that my program comments tend to be brief; as programmers we get paid to write code, not comments, so my opinion is that comments should serve to describe the purpose of the code, not simply replicate the often self-evident purpose of an instruction. For those that may think me insensitive to newcomers, I'm not -- that listing is from one of my N&V columns where all of the code is described in great detail.
As a beginner in PASM I can't hope to spot all my errors - that's the nature of being a beginner. However, I have taken your advice and deleted all the code so that other beginners don't miss out on the fun.
By the way, I'm a teacher, not a programmer. So from one profession to another can I suggest that "self evident" is not something that I would ever assume when teaching.
Cheers
Richard
'' Blame no-one but me for this code '' Richard G3CWI CON _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 var long cog long blinkpin[2] ' pin used by blinker cog long ontiming ' pin "on" timing in milliseconds long offtiming ' pin "off" timing in milliseconds Pub Main start (2, 3, 500, 200) Repeat pub start(pin0, pin1 , onms, offms) '' Start blinking pin with specified on and off durations (in milliseconds) stop ' stop if already running blinkpin[0] := pin0 blinkpin[1] := pin1 ontiming := clkfreq / 1000 * onms offtiming := clkfreq / 1000 * offms result := cog := cognew(@blinker, @blinkpin[0]) ' start blinker cog pub stop '' Stops blinker cog if running if (cog) cogstop(cog~ - 1) ' stop cog, clear id pub active '' Returns true if blinker is active return (cog > 0) dat org 0 'Set start point for PASM blinker mov t0, par ' start of structure mov t1, par ' addr in PAR => t1 rdlong t2, t1 ' read blink pin0 mov t3, #1 shl t3, t2 add t1, #4 ' go to next address rdlong t4, t1 ' read blink pin1 mov t5, #1 shl t5, t4 or t5, t3 rdlong pinmask, t5 add t0, #8 ' point to "on" ticks rdlong ontix, t0 ' read on timing add t0, #4 ' point to "off" ticks rdlong offtix, t0 ' read off timing mov dira, t3 ' make pin an output or outa, t3 ' start on mov timer, ontix ' start with on time add timer, cnt ' sync with system counter bloop waitcnt timer, offtix ' let on time expire, load off time andn outa, pinmask ' pin off waitcnt timer, ontix ' let off time expire, load on time or outa, pinmask ' pin on jmp #bloop 'jump back to bloop label to rerun loop ' -------------------------------------------------------------------------------------------------- ''Reserve longs for variables pinmask res 1 ontix res 1 ''on timing in system ticks offtix res 1 ''off timing in system ticks timer res 1 ''used to set timing t0 res 1 ''temporary variable t1 res 1 ''temporary variable t2 res 1 ''temporary variable t3 res 1 ''temporary variable t4 res 1 ''temporary variable t5 res 1 ''temporary variable fit 496No doubt some silly mistake(s).
Cheers
Richard
-Phil
That does not work so there is something else up.
Cheers
Richard
-Phil
Edit - changing the value passed to pin0 gives the expected results. Changing the value passed to pin1 does nothing.
Cheers
Richard
-Phil
I noticed the cog variable is not used consistently between the start and stop routine. In the start routine you are setting it to the return value from cognew, which is 0 to 7 if it succeeds and -1 if it fails. The stop routine assumes the value is 1 through 8 if the cog is active, and 0 if it is not.
I have realised that it is a Prop BoE thing. I had not realised that some LEDS are active low and some are active high. It was only after writing here that I started to wonder if the problem was hardware related. I was convinced my software was at fault. Now I'm back on track - thanks.
Re the start and stop problem - thanks for that. I did not write the core code so someone else is responsible for that problem!
Cheers
Richard
-Phil
All is working now.
Regards
Richard
I tend to make the dangerous assumption that those interested in programming have a willingness to crack open the manual!
IMHO, more verbose is not always simpler. Here's how you can have two pins doing the same thing -- and only one additional cog variable is used (mask for the second pin). Note, too, that as the pins and timing variables are not needed after the .start method, those can be disposed of, too.
'' ================================================================================================= '' '' File....... blinker2.spin '' Purpose.... PASM LED blinker '' Author..... '' E-mail..... '' Started.... '' Updated.... '' '' ================================================================================================= var long cog pub start(pin0, pin1, onms, offms) | ok '' Start blinking two pins with specified on and off durations (in milliseconds) stop ' stop if already running onms *= clkfreq / 1000 ' convert to system ticks offms *= clkfreq / 1000 ok := cog := cognew(@blinker, @pin0) + 1 ' start blinker cog waitcnt(clkfreq >> 10 + cnt) ' let cog start return ok pub stop '' Stops blinker cog if running if (cog) cogstop(cog - 1) ' stop cog, clear id cog := 0 pub active '' Returns true if blinker is active return (cog > 0) con dat org 0 blinker mov t1, par ' copy hub address of parameters rdlong t2, t1 ' read blink pin0 mov pinmask0, #1 ' create mask from pin # shl pinmask0, t2 mov dira, pinmask0 ' set to output add t1, #4 ' point to pin1 rdlong t2, t1 ' read blink pin1 mov pinmask0, #1 ' create mask from pin # shl pinmask0, t2 or dira, pinmask1 ' include pin1 in outputs add t1, #4 ' point to "on" ticks rdlong ontix, t1 ' read on timing add t1, #4 ' point to "off" ticks rdlong offtix, t1 ' read off timing or outa, pinmask0 ' start with pins on or outa, pinmask1 mov timer, ontix ' start with "on" time add timer, cnt ' sync with system counter bloop waitcnt timer, offtix ' let on timer expire, load off time andn outa, pinmask0 ' pins off andn outa, pinmask1 waitcnt timer, ontix ' let off timer expire, load on time or outa, pinmask0 ' pins on or outa, pinmask1 jmp #bloop ' loop forever ' -------------------------------------------------------------------------------------------------- pinmask0 res 1 ' mask for blinker pin0 pinmask1 res 1 ' mask for blinker pin1 ontix res 1 ' on timing in system ticks offtix res 1 ' off timing in system ticks timer res 1 t1 res 1 t2 res 1 fit 496 dat {{ Terms of Use: MIT License Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. }}Commenting the intent makes the program very discoverable, and that's really the goal as anyone can run tests, look up the instruction definitions, etc...
"ADD" is pretty self evident. What is being added and why isn't.