Hi Jazzed. Good point. We may need to do that. We could easily give up the pins on the Demo Board for TV use..It could be worth it to dedicate a cog at the "upper end of the spectrum." Thanks for the method reminder.
I just took Heater's code (as he tweaked it throughout this thread) and changed the way the pin number was passed.
main pgm
'Example of eight cooperative tasks in Spin.
'
CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
VAR
long OneMS
long TimeBase
OBJ
'Create 8 instances of the LED flasher task object
task_led_0 : "task_led_flasher"
task_led_1 : "task_led_flasher"
task_led_2 : "task_led_flasher"
task_led_3 : "task_led_flasher"
task_led_4 : "task_led_flasher"
task_led_5 : "task_led_flasher"
task_led_6 : "task_led_flasher"
task_led_7 : "task_led_flasher"
PUB start
'Initialize 8 LED flasher tasks with different LED pins
'and flash periods.
[COLOR=red]dira[16..23]~~[/COLOR]
task_led_0.init([COLOR=red]16[/COLOR], 100)
task_led_1.init([COLOR=red]17[/COLOR], 110)
task_led_2.init([COLOR=red]18[/COLOR], 120)
task_led_3.init([COLOR=red]19[/COLOR], 130)
task_led_4.init([COLOR=red]20[/COLOR], 140)
task_led_5.init([COLOR=red]21[/COLOR], 150)
task_led_6.init([COLOR=red]22[/COLOR], 160)
task_led_7.init([COLOR=red]23[/COLOR], 170)
OneMS := clkfreq / 1000 'Calculate cycles per 1 millisecond
TimeBase := cnt 'Get current count
'Repeatedly run each tasks run method every 1ms
repeat
waitcnt(TimeBase += OneMS) 'Wait to start of next millisecond
task_led_0.run
task_led_1.run
task_led_2.run
task_led_3.run
task_led_4.run
task_led_5.run
task_led_6.run
task_led_7.run
task_led_flasher.spin
'LED flasher cooperative task.
CON
'Possible task states.
STATE_OFF = 0
STATE_ON = 1
VAR
LONG state 'State of the task
LONG ms 'Count milliseconds here
LONG led 'Pin to use for a LED
LONG period 'Flash period
'Call this first to initialize the task.
PUB init(_led, _period)
[COLOR=red]led := |< _led 'Decode pin number[/COLOR]
period := _period
DIRA |= led
'Call this every millisecond to "kick" the task along
'N.B. Tasks may not hang up for long periods in repeat loops
' Rather they would peform one iteration of a loop on each call
' remembering the task state and iteration count ready for the next call.
PUB run
ms++
case state
STATE_OFF:
if (ms // period) == 0
OUTA |= led 'Put LED on
state := STATE_ON
STATE_ON:
if (ms // period) == 0
OUTA &= !led 'Put LED off
state := STATE_OFF
OTHER:
'WTF?
Hi Ron, now I see what you're thinking with the posted code. It does make pin and LED identification much easier.
Strange thing happened today. I came back to run the programs that have two files and none of the programs would run correctly. I still haven't figured it out.
I have both files in the same folder, so there shouldn't be a problem. One program does not run at all (no led light) and the second program does a quick blink on pin p7 (yesterday it was blinking p0 through p7). I'll see about getting this to work today.
Make sure you select the Top Object File (right click the tab of the top most program)
Thanks Ron, I tried that but no effect. I started over with the program, made all the revisions again, and it's still not working - very odd indeed. Since LED 8 is doing some quick blinking, it appears the program is doing something. I'll look at it a third time and wear out the prop book some more, but may need to wait for Heater's help on this one.
Sorry to be a bolt out of the blue, but PJV wrote the PropRTOS for the Propeller Contest and can do this independenly for many, many LEDs. His example claims over a hundred, and demos 8 in code.
Heater, thanks for the suggestions. I commented out all the tasks except the LED on pin 0. Running the program, LED on pin 0 lights up, but no blinking. The bug could be in task_led_flasher.
This code for task_led_flasher is even simpler -
the "run" method is 3 lines...
'Example of eight cooperative tasks in Spin.
'
CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
VAR
long OneMS
long TimeBase
OBJ
'Create 8 instances of the LED flasher task object
task_led_0 : "task_led_flasher"
task_led_1 : "task_led_flasher"
task_led_2 : "task_led_flasher"
task_led_3 : "task_led_flasher"
task_led_4 : "task_led_flasher"
task_led_5 : "task_led_flasher"
task_led_6 : "task_led_flasher"
task_led_7 : "task_led_flasher"
PUB start
'Initialize 8 LED flasher tasks with different LED pins
'and flash periods.
dira[16..23]~~
task_led_0.init(16, 100)
task_led_1.init(17, 110)
task_led_2.init(18, 120)
task_led_3.init(19, 130)
task_led_4.init(20, 140)
task_led_5.init(21, 150)
task_led_6.init(22, 160)
task_led_7.init(23, 170)
OneMS := clkfreq / 1000 'Calculate cycles per 1 millisecond
TimeBase := cnt 'Get current count
'Repeatedly run each tasks run method every 1ms
repeat
waitcnt(TimeBase += OneMS) 'Wait to start of next millisecond
task_led_0.run
task_led_1.run
task_led_2.run
task_led_3.run
task_led_4.run
task_led_5.run
task_led_6.run
task_led_7.run
'LED flasher cooperative task.
CON
VAR
LONG ms 'Count milliseconds here
LONG led 'Pin to use for a LED
LONG period 'Flash period
'Call this first to initialize the task.
PUB init(_led, _period)
led := _led
period := _period
DIRA[led]~~
'Call this every millisecond to "kick" the task along
'N.B. Tasks may not hang up for long periods in repeat loops
' Rather they would peform one iteration of a loop on each call
' remembering the task state and iteration count ready for the next call.
PUB run
ms++
if (ms // period) == 0
!OUTA[led] 'toggle led
Could we also please cut down the main object a bit like this (tested on the demoboard)?
'Example of eight cooperative tasks in Spin.
'
CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
VAR
long OneMS
long TimeBase
OBJ
'Create 8 instances of the LED flasher task object
task_led[8]: "task_led_flasher"
PUB start | n
'Initialize 8 LED flasher tasks with different LED pins
'and flash periods.
dira[16..23]~~
repeat n from 0 to 7
task_led[n].init(16 + n, 100 + n * 10)
OneMS := clkfreq / 1000 'Calculate cycles per 1 millisecond
TimeBase := cnt 'Get current count
'Repeatedly run each tasks run method every 1ms
repeat
waitcnt(TimeBase += OneMS) 'Wait to start of next millisecond
repeat n from 0 to 7
task_led[n].run
Hi Ron, I ran the code on a Demo Board just now and this shorter version is working. I personally think you have a monopoly on magic wands. I look forward to loading the code with more threads and exploring it in more detail when I get the new prop circuit up and running with 32 lights. You know, this is a clever program because it's down to the minimum number of code statements and it's going to make task loading and adding other functions more easy.
I am using it on the demo board which is why I use pins 16 to 23
Ron, I noticed that and it's a good thing too because you can test it and see if it works and because I have a demo board too for compatibility. It just makes things go more smooth.
Kuroneko wrote: Could we also cut down the main object a bit like this (tested on the demoboard)?
Yes we could. Great programming and testing. It looks and works very efficient and the thought you put into this is appreciated. This file makes a good companion file Ron's recent file entry. Keeping the code efficient like this is a plus, as we're working inside one cog for the 8 threads, and plan a future expansion.
Kuroneko's EDIT: Could we also please cut down the main object a bit like this (tested on the demoboard)? Last edited by kuroneko; Today at 06:20 PM. Reason: be more polite
Kuroneko, (thank you for your added politeness) I see you added the word "please" by special edit. It is amazing you did that (one small word - it almost went unnoticed) and it's very kind of you, and thank you very much for being polite. There are many good lessons to learn from you, in addition to Spin programming.
PUB run
ms++
if (ms // period) == 0
!OUTA[led] 'toggle led
Probably not too important for the intended use but ms++ will overflow at some point and depending on period this will result in the on/off period being slightly inaccurate. May I suggest something like:
Probably not too important for the intended use but ms++ will overflow at some point and depending on period this will result in the on/off period being slightly inaccurate. May I suggest something like:
PUB run
ms++
ifnot ms //= period
!outa[led]
Actually I believe the timing is important as the flashing of LEDs is only to verify the threads are working. The actual LEDs will be replaced with other routines that may have real time clocks and other timing sensitive code. Thank you for deriving this important improvement to the code.
Yes you can cut the run method down. Ultimately this whole program all but disappears. But the whole point of the example was to show a way of creating independent tasks that had their own state machine. Without needing multiple COGs and state implicitly maintained by the Spin program counters.
kuroneko,
Similarly and array of LED tasks is a neat idea but in the general case the tasks are not all the same.
It just looked so annoyingly verbose I couldn't resist
I am, aren't I?:)
Now if only Spin objects had inheritance all kinds of different task objects could inherit a "run" method from a "task"object and be handled in an array as you suggest.
I bet someone here knows a sneaky way to fool Spin into doing that.
Ron Czapala, Yes you can cut the run method down. Ultimately this whole program all but disappears. But the whole point of the example was to show a way of creating independent tasks that had their own state machine. Without needing multiple COGs and state implicitly maintained by the Spin program counters. kuroneko, Similarly <an> array of LED tasks is a neat idea but in the general case the tasks are not all the same.
Heater, this is a good point because LEDs will be substituted with actual processing tasks all happening independently in a single cog.
How shall I refer to each of the two Spin files? A Method file that calls the Object file?
And most importantly, which version of each file best represents and accomplishes "creating independent tasks that have their own state machine without needing multiple COGs, and state implicitly maintained by the Spin program counters?"
"One tiny spin program in 1 cog multi-tasks 2 simple and separate activities - blinking 2 LEDs. Blinking rate can be slow: half second on/off for one LED, 1 second on/off for the other. What is the smallest code example to do this?"
Humanoido's goal seems to have evolved from just blinking LEDs to some sort of task manager. Until his specific program requirements are defined (maintaining state, parallel processing with mutliple cogs, etc) we can only speculate what the best approach may be...
Until the spec is tightened up almost any solution will do:)
I was rather concentrating on the "separate activities" and "multi-tasks" which I take to mean they have their own state. "one cog" meaning we don't have the luxury of real multi tasking. "spin program", we have to do it in Spin.
Edit: My introduction of a state variable was just to hint that this could be expanded to more complicated tasks.
The last system I worked on before I retired was an Intranet application using Visual Studio, SQLSERVER, HTML, Visual Basic, IIS servers, Javascript, and message queues (between IBM mainframes using CICS to web applications).
Part of our requirements was a stateless programming model because a user might start an update activity but never complete it.
So depending on your needs, stateless vs stateful becomes an issue.
The devil is in the details...:smilewinkgrin:
EDIT: In fact, it is easy to imagine a scenario where trying to maintain state using a variable could introduce a bug. Since the pins are shared resources between cogs, one cog might set an output pin high and save that state in a variable. The next cog may be monitoring a sensor and deterimine that pin needs to be set low. When the first cog gets control and checks the state variable, it indicates the pin is high when actually it is low. The propeller makes it easy to check the pin's status.
Comments
humanoido
And use the bitwise decode operator set the led value
Not sure what you mean by
I just took Heater's code (as he tweaked it throughout this thread) and changed the way the pin number was passed.
main pgm
task_led_flasher.spin
Strange thing happened today. I came back to run the programs that have two files and none of the programs would run correctly. I still haven't figured it out.
I have both files in the same folder, so there shouldn't be a problem. One program does not run at all (no led light) and the second program does a quick blink on pin p7 (yesterday it was blinking p0 through p7). I'll see about getting this to work today.
Humanoido
Humanoido
Try the attached versions which includes Ron's pin decode mod and splits the init and run parts of the main program into separate methods.
Can't immediately see what's up. Try commenting out all the run methods except one. Then a different one. etc.
http://www.parallax.com/PropRTOS/tabid/852/Default.aspx
the "run" method is 3 lines...
the "run" method is 3 lines...
Ron, this is fantastic but I have one question - did you run it on your prop board and did it test "working"?
I will try the code in a few minutes..
Humanoido
Yes we could. Great programming and testing. It looks and works very efficient and the thought you put into this is appreciated. This file makes a good companion file Ron's recent file entry. Keeping the code efficient like this is a plus, as we're working inside one cog for the 8 threads, and plan a future expansion.
Humanoido
Kuroneko, (thank you for your added politeness) I see you added the word "please" by special edit. It is amazing you did that (one small word - it almost went unnoticed) and it's very kind of you, and thank you very much for being polite. There are many good lessons to learn from you, in addition to Spin programming.
Humanoido
Humanoido
Yes you can cut the run method down. Ultimately this whole program all but disappears. But the whole point of the example was to show a way of creating independent tasks that had their own state machine. Without needing multiple COGs and state implicitly maintained by the Spin program counters.
kuroneko,
Similarly and array of LED tasks is a neat idea but in the general case the tasks are not all the same.
Point taken. It just looked so annoyingly verbose I couldn't resist
I am, aren't I?:)
Now if only Spin objects had inheritance all kinds of different task objects could inherit a "run" method from a "task"object and be handled in an array as you suggest.
I bet someone here knows a sneaky way to fool Spin into doing that.
How shall I refer to each of the two Spin files? A Method file that calls the Object file?
And most importantly, which version of each file best represents and accomplishes "creating independent tasks that have their own state machine without needing multiple COGs, and state implicitly maintained by the Spin program counters?"
Humanoido
"One tiny spin program in 1 cog multi-tasks 2 simple and separate activities - blinking 2 LEDs. Blinking rate can be slow: half second on/off for one LED, 1 second on/off for the other. What is the smallest code example to do this?"
Humanoido's goal seems to have evolved from just blinking LEDs to some sort of task manager. Until his specific program requirements are defined (maintaining state, parallel processing with mutliple cogs, etc) we can only speculate what the best approach may be...
Since he was having trouble getting the program to run (which worked fine after you made the change in post #20 http://forums.parallax.com/showpost.php?p=933016&postcount=20), I simplified the code in his search for the "smallest code".
In this particular program, the state of an output pin can be checked using something like "if outa[led]" rather keeping the value in a variable.
Until the spec is tightened up almost any solution will do:)
I was rather concentrating on the "separate activities" and "multi-tasks" which I take to mean they have their own state. "one cog" meaning we don't have the luxury of real multi tasking. "spin program", we have to do it in Spin.
Edit: My introduction of a state variable was just to hint that this could be expanded to more complicated tasks.
Part of our requirements was a stateless programming model because a user might start an update activity but never complete it.
So depending on your needs, stateless vs stateful becomes an issue.
The devil is in the details...:smilewinkgrin:
EDIT: In fact, it is easy to imagine a scenario where trying to maintain state using a variable could introduce a bug. Since the pins are shared resources between cogs, one cog might set an output pin high and save that state in a variable. The next cog may be monitoring a sensor and deterimine that pin needs to be set low. When the first cog gets control and checks the state variable, it indicates the pin is high when actually it is low. The propeller makes it easy to check the pin's status.