I think I will put together a YouTube video so people can follow along where turn single led on, and final step is a full-blown pwm trailing led knightrider
Here is step3, (it does not use OR/ANDN for pins yet) Questions?
CON_clkmode = xtal1 + pll16x'Standard clock mode * crystal frequency = 80 MHz_xinfreq = 5_000_000VARlong symbol 'not used yetPUBStartRidercognew(@entry,0) 'cognew needs two varibles, the start address of pasm code and a (optional) varible to pass alongDATorg0
entry movDIRA,_mypins 'set LED control pins P16-P23 as output
main mov t1,#7'run loop 7 times, so set varible t1 to 7
loop movOUTA,_pin 'set the LED we want onmov t2,cnt'copy current Prop Master Counter value to t2add t2,_delay 'add a 1/16sec delay waitcnt t2,0'tell cog to wait until MasterCounter match t2
shifter shl _pin,#1'shift left 7 times and then shift right 7 times.djnz t1,#loop 'so do 7 in a row, if not at at 0 jmp to loopxor shifter,_bit26 'self-mod the shl into a shrjmp #main 'jmp to main, don't forget the #
_bit26 long1<<26'same as |<26
_mypins long%11111111<<16'same as %00000000_11111111_00000000_00000000
_pin long |<16'same as %00000000_00000001_00000000_00000000
_delay long80_000_000/16'80 mill (MHz) divided by 16 = 1/16sec
t1 res'reserve a temp var, will be initiated to a value by code
t2 res
With everyone help, I have decided to put this board away for a little bit, and use PSAM to get me started learning. Then after I start getting the hang of it, bringing out the Atmel board and start playing with it.
A useful way to learn Assembler (on any micro), is with a Good Simulator.
Some of the better tool flows let you mix HLL and the created Assembler, in the Simulator/Debug, but most will give listings of Source and created-Assembler.
I think the AVR Studio includes a Simulator.
Another easy-access path into small micros (which can be useful next to a Prop ) is something like TOOLSTICK850-B-SK
That is ~ $10, and gives you USB-hardware debug access, into a small, sub $1 uC with 12b ADC UART SPI i2c PWM Timers etc.
Tools are all free.
I agree with jmg. An alternative is to use a framework, or template where things like getting output or taking input are solved, leaving just the important guts to learn about.
One of the reasons I did character drivers on the Prop, was to build a little PASM framework like I always had or did on older machines.
This is also why blinking the LED, then controlling the blink, and finally, blinking in response to input is the "coming of age" trifecta usually able to get somebody going in assembly language.
On the P1, SPIN is really awesome in how PASM gets loaded onto a COG, making extremely lean, simple and effective PASM programs possible.
We will very likely have in-line PASM on the next chip, which is the only easier thing I have ever encountered.
(more, I just realized I need to change batteries... brb, don't want to lose what I have written)
The next best thing really is a starter template or two. The one TonyP put out there is a nice start. Adding the basic code to take a value from PAR would flesh it out to be a nice starting point for almost anything.
From there, it's a one or two strategy approach.
If you've got a simulator, great! Use it to run your template and understand everything it does. Then, you can take that template, drop new instructions into it and learn what they do.
If you don't have a simulator, then you work through the template, changing things, and following all of what it does through, until you understand what it's doing. Then, you drop new instructions in, and output results you can use to understand them.
One basic skill is thinking up quick, clever tests to determine whether or not something is happening. This is the debug LED basically. Based on this, or that, it can be turned on, or off, and with just that LED, you can understand the instructions pretty well, and find out what your program is doing.
To be a good asm programmer you must be able to see that it must be a bit pattern somewhere.
Here is the above code again, but without a loop as it ANDs (TEST) pin variable with %10000001 to see if result is 0.
DATorg0
entry movDIRA,_mypins 'set LED control pins P16-P23 as output
main movOUTA,_pin 'set the LED we want onmov t2,cnt'copy current Prop Master Counter value to t2add t2,_delay 'add a 1/16sec delay waitcnt t2,0'tell cog to wait until MasterCounter match t2
shifter shl _pin,#1'shift left 7 times and then shift right 7 times.test _pin,_ends wz'if pin is at any place of x in 0xxxxxxx0, the result is that z is set if_nzxor shifter,_bit26 'self-mod the shl into a shrjmp #main 'jmp to main, don't forget the #
_bit26 long1<<26'same as |<26
_mypins long%11111111<<16'same as %00000000_11111111_00000000_00000000
_pin long |<16'same as %00000000_00000001_00000000_00000000
_ends long%10000001<<16'same as %00000000_10000001_00000000_00000000
_delay long80_000_000/16'80 mill (MHz) divided by 16 = 1/16sec
t2 res'reserve a temp var, will be initiated to a value by code
It certainly doesn't hurt to focus on programing in just one Cog until you see an obvious need for more.
Assembly language focuses on what the CPU is doing and you have 8 of them available. Too many CPUs doing many things may get you caught up in passing data back and forth rather than in learning to control the CPU.
When you do move on to more than one CPU, spending a lot of time with just TWO may make sense to fully leaarn how Cogs do share.
In other words, try to have a study model that offers you the ability to clearly visualize what is going on, and what your resources are really doing.
Same function as above, but with a look-up table (resulting that any/many LEDs could be on at the same time as you have complete animation control)
DATorg0
entry movDIRA,_mypins 'set LED control pins P16-P23 as output
main mov t1,#14'run loop 14 times, so set varible t1 to 14movs animator,#_pin_table 'reset the look-up-table address in self-mod code 0-0, don't forget the mov[b]s[/b] and the #
loop mov t2,cnt'copy current Prop Master Counter value to t2add t2,_delay 'add a 1/14sec delay waitcnt t2,0'tell cog to wait until MasterCounter match t2
animator movOUTA,0-0'set the LED we want onadd animator,#1'next table byte (longs are "bytes" in cogs)djnz t1,#loop 'so do 14 in a row, if not at at 0 jmp to loopjmp #main 'jmp to main, don't forget the #
_pin_table long%00000001<<16, %00000010<<16, %00000100<<16, %00001000<<16, %00010000<<16, %00100000<<16, %01000000<<16long%10000000<<16, %01000000<<16, %00100000<<16, %00010000<<16, %00001000<<16, %00000100<<16, %00000010<<16
_mypins long%11111111<<16'same as %00000000_11111111_00000000_00000000
_delay long80_000_000/14'80 mill (MHz) divided by 14 = 1/14sec
t1 res'reserve a temp var, will be initiated to a value by code
t2 res'reserve a temp var, will be initiated to a value by code
Same look-up table, but it's in HUB and the array's start @address is passed along with PAR, Spin can now modify the table on the fly as this memory space is continuously read by the cog
CON_clkmode = xtal1 + pll16x'Standard clock mode * crystal frequency = 80 MHz_xinfreq = 5_000_000VARlong pin_table[14] ' reserve a 14 long arrayPUBStartRider
PrepareTable 'run the subroutine below to setup a knightrider animationcognew(@entry,@pin_table) 'cognew needs two varibles, the start address of pasm code and a (optional) varible to pass alongPUBPrepareTable
pin_table[0] := %00000001<<16
pin_table[1] := %00000010<<16
pin_table[2] := %00000100<<16
pin_table[3] := %00001000<<16
pin_table[4] := %00010000<<16
pin_table[5] := %00100000<<16
pin_table[6] := %01000000<<16
pin_table[7] := %10000000<<16
pin_table[8] := %01000000<<16
pin_table[9] := %00100000<<16
pin_table[10]:= %00010000<<16
pin_table[11]:= %00001000<<16
pin_table[12]:= %00000100<<16
pin_table[13]:= %00000010<<16DATorg0
entry movDIRA,_mypins 'set LED control pins P16-P23 as output
main mov t1,#14'run loop 14 times, so set varible t1 to 14mov hubpnt,PAR'use the address in PAR that was passed along when cognew
loop mov t2,cnt'copy current Prop Master Counter value to t2add t2,_delay 'add a 1/12sec delay waitcnt t2,0'tell cog to wait until MasterCounter match t2rdlongOUTA,hubpnt 'set the LED we want onadd hubpnt,#4'next table long (longs are 4 bytes in hub)djnz t1,#loop 'so do 14 in a row, if not at at 0 jmp to loopjmp #main 'jmp to main, don't forget the #
_mypins long%11111111<<16'same as %00000000_11111111_00000000_00000000
_delay long80_000_000/12'80 mill (MHz) divided by 14 = 1/12sec
hubpnt res'PAR is read-only and can not be incremented, plus we need its original value later on anyway
t1 res'reserve a temp var, will be initiated to a value by code
t2 res'reserve a temp var, will be initiated to a value by code
Comments
Here is step3, (it does not use OR/ANDN for pins yet) Questions?
CON _clkmode = xtal1 + pll16x 'Standard clock mode * crystal frequency = 80 MHz _xinfreq = 5_000_000 VAR long symbol 'not used yet PUB StartRider cognew(@entry,0) 'cognew needs two varibles, the start address of pasm code and a (optional) varible to pass along DAT org 0 entry mov DIRA,_mypins 'set LED control pins P16-P23 as output main mov t1,#7 'run loop 7 times, so set varible t1 to 7 loop mov OUTA,_pin 'set the LED we want on mov t2,cnt 'copy current Prop Master Counter value to t2 add t2,_delay 'add a 1/16sec delay waitcnt t2,0 'tell cog to wait until MasterCounter match t2 shifter shl _pin,#1 'shift left 7 times and then shift right 7 times. djnz t1,#loop 'so do 7 in a row, if not at at 0 jmp to loop xor shifter,_bit26 'self-mod the shl into a shr jmp #main 'jmp to main, don't forget the # _bit26 long 1<<26 'same as |<26 _mypins long %11111111<<16 'same as %00000000_11111111_00000000_00000000 _pin long |<16 'same as %00000000_00000001_00000000_00000000 _delay long 80_000_000/16 '80 mill (MHz) divided by 16 = 1/16sec t1 res 'reserve a temp var, will be initiated to a value by code t2 res
A useful way to learn Assembler (on any micro), is with a Good Simulator.
Some of the better tool flows let you mix HLL and the created Assembler, in the Simulator/Debug, but most will give listings of Source and created-Assembler.
I think the AVR Studio includes a Simulator.
Another easy-access path into small micros (which can be useful next to a Prop ) is something like TOOLSTICK850-B-SK
That is ~ $10, and gives you USB-hardware debug access, into a small, sub $1 uC with 12b ADC UART SPI i2c PWM Timers etc.
Tools are all free.
useful simulators for this 8 bit core are
http://www.ieap.uni-kiel.de/surface/ag-berndt/lehre/fpmc/index-e.html
and
http://turbo51studio.orgfree.com/downloads/turbo51studio-latest-setup.zip
One of the reasons I did character drivers on the Prop, was to build a little PASM framework like I always had or did on older machines.
This is also why blinking the LED, then controlling the blink, and finally, blinking in response to input is the "coming of age" trifecta usually able to get somebody going in assembly language.
On the P1, SPIN is really awesome in how PASM gets loaded onto a COG, making extremely lean, simple and effective PASM programs possible.
We will very likely have in-line PASM on the next chip, which is the only easier thing I have ever encountered.
(more, I just realized I need to change batteries... brb, don't want to lose what I have written)
http://www.iar.com/Products/IAR-Embedded-Workbench/
From there, it's a one or two strategy approach.
If you've got a simulator, great! Use it to run your template and understand everything it does. Then, you can take that template, drop new instructions into it and learn what they do.
If you don't have a simulator, then you work through the template, changing things, and following all of what it does through, until you understand what it's doing. Then, you drop new instructions in, and output results you can use to understand them.
One basic skill is thinking up quick, clever tests to determine whether or not something is happening. This is the debug LED basically. Based on this, or that, it can be turned on, or off, and with just that LED, you can understand the instructions pretty well, and find out what your program is doing.
Here is the above code again, but without a loop as it ANDs (TEST) pin variable with %10000001 to see if result is 0.
DAT org 0 entry mov DIRA,_mypins 'set LED control pins P16-P23 as output main mov OUTA,_pin 'set the LED we want on mov t2,cnt 'copy current Prop Master Counter value to t2 add t2,_delay 'add a 1/16sec delay waitcnt t2,0 'tell cog to wait until MasterCounter match t2 shifter shl _pin,#1 'shift left 7 times and then shift right 7 times. test _pin,_ends wz 'if pin is at any place of x in 0xxxxxxx0, the result is that z is set if_nz xor shifter,_bit26 'self-mod the shl into a shr jmp #main 'jmp to main, don't forget the # _bit26 long 1<<26 'same as |<26 _mypins long %11111111<<16 'same as %00000000_11111111_00000000_00000000 _pin long |<16 'same as %00000000_00000001_00000000_00000000 _ends long %10000001<<16 'same as %00000000_10000001_00000000_00000000 _delay long 80_000_000/16 '80 mill (MHz) divided by 16 = 1/16sec t2 res 'reserve a temp var, will be initiated to a value by code
Assembly language focuses on what the CPU is doing and you have 8 of them available. Too many CPUs doing many things may get you caught up in passing data back and forth rather than in learning to control the CPU.
When you do move on to more than one CPU, spending a lot of time with just TWO may make sense to fully leaarn how Cogs do share.
In other words, try to have a study model that offers you the ability to clearly visualize what is going on, and what your resources are really doing.
DAT org 0 entry mov DIRA,_mypins 'set LED control pins P16-P23 as output main mov t1,#14 'run loop 14 times, so set varible t1 to 14 movs animator,#_pin_table 'reset the look-up-table address in self-mod code 0-0, don't forget the mov[b]s[/b] and the # loop mov t2,cnt 'copy current Prop Master Counter value to t2 add t2,_delay 'add a 1/14sec delay waitcnt t2,0 'tell cog to wait until MasterCounter match t2 animator mov OUTA,0-0 'set the LED we want on add animator,#1 'next table byte (longs are "bytes" in cogs) djnz t1,#loop 'so do 14 in a row, if not at at 0 jmp to loop jmp #main 'jmp to main, don't forget the # _pin_table long %00000001<<16, %00000010<<16, %00000100<<16, %00001000<<16, %00010000<<16, %00100000<<16, %01000000<<16 long %10000000<<16, %01000000<<16, %00100000<<16, %00010000<<16, %00001000<<16, %00000100<<16, %00000010<<16 _mypins long %11111111<<16 'same as %00000000_11111111_00000000_00000000 _delay long 80_000_000/14 '80 mill (MHz) divided by 14 = 1/14sec t1 res 'reserve a temp var, will be initiated to a value by code t2 res 'reserve a temp var, will be initiated to a value by code
CON _clkmode = xtal1 + pll16x 'Standard clock mode * crystal frequency = 80 MHz _xinfreq = 5_000_000 VAR long pin_table[14] ' reserve a 14 long array PUB StartRider PrepareTable 'run the subroutine below to setup a knightrider animation cognew(@entry,@pin_table) 'cognew needs two varibles, the start address of pasm code and a (optional) varible to pass along PUB PrepareTable pin_table[0] := %00000001<<16 pin_table[1] := %00000010<<16 pin_table[2] := %00000100<<16 pin_table[3] := %00001000<<16 pin_table[4] := %00010000<<16 pin_table[5] := %00100000<<16 pin_table[6] := %01000000<<16 pin_table[7] := %10000000<<16 pin_table[8] := %01000000<<16 pin_table[9] := %00100000<<16 pin_table[10]:= %00010000<<16 pin_table[11]:= %00001000<<16 pin_table[12]:= %00000100<<16 pin_table[13]:= %00000010<<16 DAT org 0 entry mov DIRA,_mypins 'set LED control pins P16-P23 as output main mov t1,#14 'run loop 14 times, so set varible t1 to 14 mov hubpnt,PAR 'use the address in PAR that was passed along when cognew loop mov t2,cnt 'copy current Prop Master Counter value to t2 add t2,_delay 'add a 1/12sec delay waitcnt t2,0 'tell cog to wait until MasterCounter match t2 rdlong OUTA,hubpnt 'set the LED we want on add hubpnt,#4 'next table long (longs are 4 bytes in hub) djnz t1,#loop 'so do 14 in a row, if not at at 0 jmp to loop jmp #main 'jmp to main, don't forget the # _mypins long %11111111<<16 'same as %00000000_11111111_00000000_00000000 _delay long 80_000_000/12 '80 mill (MHz) divided by 14 = 1/12sec hubpnt res 'PAR is read-only and can not be incremented, plus we need its original value later on anyway t1 res 'reserve a temp var, will be initiated to a value by code t2 res 'reserve a temp var, will be initiated to a value by code