Assembly Code Examples for the Beginner
Javalin
Posts: 892
Morning all,
I've just started into Propeller Assembly and I am having some issues with controlling/reading pins.
I can set a pin high using
But how do I set it LOW?· I would assume from SX assembler you'd need a AND of all the pin bits bar pin10 in this case - i.e %111111111111111011111111111 (etc)· Is there an easier way to do this?
I assume the same applies to DIRA and setting input(0) and output(1) modes
Then reading pins - I am using the following code - to read INA state:
I get values back from it, but wrong ones.
As always grateful for any help!
James
Moderator Edit: By popular request this thread is being made a sticky.
Post Edited By Moderator (Chris Savage (Parallax)) : 8/21/2006 5:19:48 PM GMT
I've just started into Propeller Assembly and I am having some issues with controlling/reading pins.
I can set a pin high using
But how do I set it LOW?· I would assume from SX assembler you'd need a AND of all the pin bits bar pin10 in this case - i.e %111111111111111011111111111 (etc)· Is there an easier way to do this?
or dira, SPI_ASM_CLK ' output or outa, SPI_ASM_CLK ' HIGH .... SPI_ASM_CLK long |< 10
I assume the same applies to DIRA and setting input(0) and output(1) modes
Then reading pins - I am using the following code - to read INA state:
mov input, #0 ' Zero input or input, INA ' Place the state of all the pins into input and input, SPI_ASM_DI ' Place the state of SDA into input test input, SPI_ASM_DI WC ' If input AND SDA = 0  WZ=1 else = 1  WZ=0 if_c shl spiASMData,#1 if_c or spiASMData,#1 if_nc shl spiASMData,#1 ..... SPI_ASM_DI long |< 11
I get values back from it, but wrong ones.
As always grateful for any help!
James
Moderator Edit: By popular request this thread is being made a sticky.
Post Edited By Moderator (Chris Savage (Parallax)) : 8/21/2006 5:19:48 PM GMT
Comments
You were off by one letter!
Read the definition of XOR. Basically, only when both xor'd variable are 0's or 1's, you get a zero. When they are opposite, xor 0 with 1, you get a 1. See page 271 in the manual, then write out (like in 3rd grade arithmatic) the 32 bit "outa" and xor it with 32 bit "SPI_ASM_CLK".
If OUTA was on/high/1
OUTA
0000_0101_0011_0111_0000_0110_0110_0001
SPI_ASM_CLK--0000_0000_0000_0000_0000_0010_0000_0000
Result-OUTA----0000_0101_0011_0111_0000_0100_0110_0001
If OUTA was off/low/0
OUTA
0000_0101_0011_0111_0000_0100_0110_0001
SPI_ASM_CLK--0000_0000_0000_0000_0000_0010_0000_0000
Result-OUTA----0000_0101_0011_0111_0000_0110_0110_0001
In assy, it is simply the easiest way to toggle a pin state.
-Parsko
Post Edited (parsko) : 8/20/2006 11:42:23 AM GMT
Doesn't that mean that i would need to know the state of the pin before I try to set it high or low?
Im not looking to toggle, but to set the pin state.
Thanks,
James
Thanks thats what I was after!
James
Sorry, I thought you just wanted to toggle it. When you set a pin to output, doesn't mean it is high, only that it is an output. Mike, I think they should add something that explicit in the manual, you said it well.
-Luke
A few more ASM examples in the manual would be helpful!
Thanks for your help!
James
'Pin' holds a value ranging between 0 and 31 corresponding to the I/O pin you want to affect.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Beau Schwabe
IC Layout Engineer
Parallax, Inc.
Post Edited (Beau Schwabe (Parallax)) : 8/21/2006 4:19:52 AM GMT
I feel that it is about time that there was an Assembly Tutorial Sticky containing examples just like this, in the same manner that there is a Spin beginners guide. A logical orgainization of it would be nice, but to have one place to look for assy examples would be more nice. I know I could post a few after my "high speed Shiftin" experiences...
-Parsko
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Beau Schwabe
IC Layout Engineer
Parallax, Inc.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Beau Schwabe
IC Layout Engineer
Parallax, Inc.
Post Edited (Beau Schwabe (Parallax)) : 8/21/2006 7:21:59 PM GMT
Thanks for the post! Very useful!
James
Please include the minimum SPIN code. Your example is not so obvious to the beginners that other stuff is necessary. I've got an easy one that might be more ahead of what you suggested to start. It will toggle a pin endlessly...
The waitcnt command KILLED me for what seemed to be weeks before the went off.
Short of what is happening to waitcnt goes like this, if one were to run through the program line for line:
The important note is that you must set the time value of waitcnt before waiting for it. The system will wait until cnt = Time. If your value for Time is less than the system counter at the time the waitcnt command is executed, the COG will pause until CNT wraps around, or about 53 seconds at 80Mhz. So, it sits there waiting, then adds Delay to Time. This is the value that will be used in the NEXT waitcnt command (aka the value used at cnt=40_000_020 above).
Gotta go set the table, more to come...
-Parsko
This Assembly demo illustrates:
1) a Simple SPI Engine (Serial Periphial Interface)
2) Setting up an "Assembly Function" method to be used within Spin
3) A method for passing variables back-n-forth between Spin and Assembly
Edit: updated SPI engine....
fixed problem with SHIFTOUT MSBFIRST option
fixed argument allocation in the SPI Engines main loop
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Beau Schwabe
IC Layout Engineer
Parallax, Inc.
Post Edited (Beau Schwabe (Parallax)) : 8/24/2006 4:40:19 AM GMT
I think we need to get this copyright thing straightened out. A lot of Propeller code origniating from Parallax (like the SPI Engine above) includes a copyright notice, but no licensing terms. The rules for the Propeller Object Exchange state "no copyrights", which implies public domain (and which is the reason I've never posted anything there). I think a copyright is important, along with a reasonable license for sharing the code. I prefer the General Public License (GPL) for this, and any significant code that I've originated and posted in various forum threads contains those terms of use.
The reasons for having a copyright are several:
1. It allows one to control the attributions that appear in the code, yielding a provenance than can be traced back to the originator.
2. It prevents someone else from copyiing the code and claiming it as their own, as could happen with code in the public domain.
3. It allows one to set restrictions on how the code may be used and distributed, keeping it "free", for example, as the GPL does.
But if copyrighted code is meant to be shared, it needs to say so, even though that intent in the context of the forum might seem clear. Once a program is copied from the forum context, any implied consent disappears. My vote would be to standardize on the GPL for shared Propeller code and to remove the "no copyrights" restriction from the object exchange in favor of that license.
I don't mean to stir up a hornet's nest here, but there are presently some inconsistencies and ambiguities that leave me a little uneasy.
Thanks,
Phil
You bring up a good point. I will find out what the proper "Header" should look like in released code from Parallax.
What I have been using for the Header of objects that I have been posting originates from objects such as 'Keyboard.spin', 'Mouse.spin', etc....
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Beau Schwabe
IC Layout Engineer
Parallax, Inc.
Notice, Marker #1 that starts a cognew at TestMode2...
Running this test I would expect LED #16 and LED #17 to turn on.
The actual result is that none of the LED's turn on.
You could change Marker #1 so that it starts a cognew at TestMode1,
and then both LED's would turn on. However for illustration purposes,
TestMode1 happens to do something similar to TestMode2, but it could
be anything.
Remarking the 'call' statement on Marker #4 will cause LED #17 to turn
on as expected and LED #16 will remain off ... as expected. SO why, since
the section between Marker 5&6 is the same as the section between 7&8, won't
this program run the way that it is without remarking the 'call' on Marker #4?
The answer is the way that 'cognew' needs to load your assembly program.
The proper way is to load or start the cog at the top most assembly code
position. In this case the line at Marker #1 should read...
...Now at TestMode1 if you want to run or start at TestMode2 then you need a
'jmp' at TestMode1 that points to TestMode2
One more thing to watch out for that has to do with the 'call' function mentioned
in the book is the way that the 'ret' gets encoded into the returning address.
If the lines between Markers 8&9 looked like this...
... Then when 'InitializePins' was actually called, this procedure would not know
where to return. Instead 'ret' MUST be on the same line as the '{Routine}_ret'
in order to properly execute.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Beau Schwabe
IC Layout Engineer
Parallax, Inc.
Post Edited (Beau Schwabe (Parallax)) : 8/22/2006 7:51:54 PM GMT
You can also pile up return labels in a subroutine with multiple entry points (or even for multiple subroutines, for that matter, if memory is really tight):
Also, if you need to branch to a subroutine's return point, you don't need to do an immediate jmp. An indirect jmp not only works fine, but saves four clocks:
The reason this works is that the return address is stored in the src field of the "return" instruction. The indirect jump just picks it up and uses it, instead of going to Sub_ret first.
-Phil
Post Edited (Mike Green) : 8/23/2006 3:37:17 PM GMT
I am still with this belief, however it is application dependent. There are certainly other
times that it is better to use 'or' or 'andn' to affect an I/O bit. The savings can be a few
clock cycles and an extra programming 'long' ...for large applications this can make a big
difference. On smaller applications sometimes you just want to get the job done and it doesn't
really matter one way or the other.
Typically to affect an I/O pin on a 32-bit register you need to create what's known as a 'mask'
To set up a mask simply initialize a mask variable to "1" and then shift that variable left by
the number of bits you wish. For an I/O this translates to the pin you want to access.
Example1:
To define an I/O pin as an input we can use the 'andn' operator AFTER we have created a 'mask'.
Example2:
By using the 'or' operator instead, we can define the I/O pin as an output.
Example3:
Using the same 'or' operator and directing it toward 'outa' instead of 'dira' we can define the
pin state as HIGH if we also make the I/O pin an output.
Example4:
Likewise if we use the 'andn' operator we can define the pin state as being LOW if we also make
the I/O pin an output.
Example5:
Suppose we want to affect an I/O pin based on a variable or another I/O pin. One way to do it
using the 'andn' and 'or' operators is to test the variable or pin with a 'mask' and write to
the 'z' flag using the 'if_z' and 'if_nz' conditionals.
Example6:
Another way to accomplish the same task is to use the 'mux' operator.
Example7:
Now, this may not seem like a huge amount of savings, but this type of scenario has a way of
multiplying itself as a program gets larger, and it can make a difference in the long run with
some applications. Example 8 is a complete Propeller assembly program of Example 7.
Example8: I/O follower
Example9: MSB - SHIFTIN
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Beau Schwabe
IC Layout Engineer
Parallax, Inc.
please see the following thread for an update to this post
http://forums.parallax.com/showthread.php?p=646675
LucidGuppy,
This example will launch a cog just to run the Assembly, then add the two numbers and stop the cog after returning the result.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Beau Schwabe
IC Layout Engineer
Parallax, Inc.
Post Edited (Beau Schwabe (Parallax)) : 4/21/2007 5:07:01 PM GMT
I'll give this a try tonight. Seems like a lot of people are way ahead of me and I need to catch up.
·Where do the results go ? and how can you "look" at them ?
Thanks , Brian
How long does it take to start/stop a new cog with an assembly program ?
If I have a routine that isn't fast enough in spin, I know it would be faster in assembly, but I don't know what the time delay is to launch a new cog.
Bean.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Cheap used 4-digit LED display with driver IC·www.hc4led.com
Low power SD Data Logger www.sddatalogger.com
SX-Video Display Modules www.sxvm.com
Stuff I'm selling on ebay http://search.ebay.com/_W0QQsassZhittconsultingQQhtZ-1
"People who are willing to trade their freedom for·security deserve neither and will lose both." Benjamin Franklin
·
The results (_Num1) are computed in a memory location within the cog's memory space (512 32-bit words). The main memory which
is used by the SPIN interpreter is separate. To the program running in the cog, the main memory looks a bit like an I/O device with
special instructions needed to access it. In particular, the "wrlong <cog address>,<hub address>" instruction writes the contents of
the specified cog location into a main (hub) memory location whose address is in a cog location (in this case, the PAR register). The PAR
register is a read-only cog memory location that contains a hub memory long-word address specified when the cog was started (by the
COGINIT/COGNEW instruction).
You can only "look" at the results of an assembly program by the assembly program itself copying the results into the common hub memory
for other programs (whether in SPIN or assembly) to examine. You could also send the results to an I/O device by manipulating the I/O pins.
Mike
If you treat 'AddNums(Num1,Num2)' as a function, then when you call it with something like...
Answer := AddNums(Num1,Num2)
Your result will be returned in the variable 'Answer'
To 'look' at them, use any of the other objects available to display them to a TV,VGA,SERIAL,LED's(binary form) etc.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Beau Schwabe
IC Layout Engineer
Parallax, Inc.
I've been in Rocklin and Tahoe all of this weekend, and while I was in the Parallax office on Friday and Monday, I was busy going over layout ideas with Chip
and did not have a chance to do any timing tests with the Propeller that would answer your question.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Beau Schwabe
IC Layout Engineer
Parallax, Inc.
I didn't actually measure the time, but it's pretty fast (much faster than the same code in spin).
I was thinking it had to load the cog from EEPROM, but now that I think about it, I guess it just loads from hub memory into cog memory (which is much faster than pulling the data from the EEPROM).
Bean.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Cheap used 4-digit LED display with driver IC·www.hc4led.com
Low power SD Data Logger www.sddatalogger.com
SX-Video Display Modules www.sxvm.com
Stuff I'm selling on ebay http://search.ebay.com/_W0QQsassZhittconsultingQQhtZ-1
"People who are willing to trade their freedom for·security deserve neither and will lose both." Benjamin Franklin
·
This code is legal. But any new cognew's that occur, must have a PARameter registered to some value of the array/4. Let me say that another way, it's late. I used "@second[noparse][[/noparse]4]" for my PARameter. I could have easily used "@second[noparse][[/noparse]0]" or "@second[noparse][[/noparse]8]". The cognew requeires the start of a long for it's parameter. So, if you want to use "@second[noparse][[/noparse]2]" it will still start at second[noparse][[/noparse]0]. Subsequently, @second[noparse][[/noparse]6] will start at @second[noparse][[/noparse]4] {The less obvious concept I'm pointing out}
-Parsko
Post Edited (parsko) : 12/10/2006 1:27:55 AM GMT