1 Core 2 Activities
Humanoido
Posts: 5,770
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?
Thanks in advance,
Humanoido
Thanks in advance,
Humanoido
Comments
But if the tasks are "cooperative" they can get along just fine.
My approach is:
1) Have one method per task.
2) Each method is called every repeatedly at some suitable iteration rate by a main loop.
3) Each task method maintains a "state variable" so that it does not forget what it was doing between calls.
4) A case statement can be used to direct activity within the task depending on the state variable.
4) Tasks may not hang up on repeat loops or waitxx.
This may seem very crude, but I have worked on Rolls-Royce jet engine management systems that were basically organized like this.
Below is a simple example for your flashing LEDs case. Only two states per task ON or OFF.
Basically set each counter to control the output of one of the pins at the desired frequencies.
Humanoido
Edit: I think I see it now, it must be a faster crystal you're using.
Added this to CON but still not blinking:
_clkmode = xtal1 + pll16x ' Feedback and PLL multiplier
_xinfreq = 5_000_000 ' External oscillator = 5 MHz
The LEDs are controlled through dira which means for the demoboard outa has to be initialised to %11 (it may well work on his h/w). The other thing is that both tasks interfere with each others LED pins.
Change the dira setup to:
This then works for me on the demoboard (adjusted for 16/17).
Thank you very much for your assistance!
Humanoido
But I think you are looking for co-operative tasking in general.
The right way would be to use a greatest common denominator time cycle.
So create a state machine that is initiated 100 times a second.
A=A+1
B=B+1
IF A>50 LED0 turned on
IF A>100 LED0 turned OFF, A=0
IF B>100 LED1 turned on
IF B>200 LED1 turned OFF, B=0
Now, if the code in the tasks gets a bit complicated and the they are very different I would be inclined to put the task methods and their associated variables into their own separate Spin files as different objects. The top level "scheduler" loop would then be in a top level object by itself.
Of course if you do that you only need to write one LED task object in this case, create two instances of it with OBJ and pass the LED flash period in as a parameter.
One "deep" thing about this technique is that if you make the rule that there can be no loops (repeat etc) in the task methods and no waitxxx then it becomes possible for some code analysis program to find all the possible pathways through each task. Including any subroutine calls. For each pathway it could know which instructions are executed and how long they take to execute. This analysis can then tell you exactly how much of the "scheduler" time tick period each task takes in the worst case. That is to say, every time you change and recompile the code the analysis can tell you if you are running out of time. For those Rolls-Royce engine projects we had just such analysis built into the compiler.
Kuroneko, no confusion, it was your comments which sorted things out, thank you. Also good that you ran the program on a Demo Board too.
Humanoido
A=A+1
B=B+1
IF A>50 LED1 turned on
IF A>100 LED1 turned OFF, A=0
IF B>100 LED1 turned on
IF B>200 LED1 turned OFF, B=0
Tony P : Definitely looks like there's a place for both counters and a greatest common denominator time cycle from within the code! It's also a clean straightforward way of embedding state machines within code using a looping technique. It can also serve to create sub-processors. Thank you for pointing this out.Humanoido
Humanoido
Good idea - it would make writing and keeping track of more tasks easier.
Heater, this is another brilliant and logical idea - we must say - that Rolls-Royce jet engine project is having a positive effect on this forum thread.
Heater, as a next step to expand the program, what is involved in putting 8 LEDs in the program, instead of only 2? (I have LEDs on p0 through p7).. hint ..hint..
Humanoido
Here is an 8 LED cooperative task scheduler example with only one actual LED flasher method with parameters to select which LED and period it should use. The flasher method is now in its own spin file as separate object. That save the confusuion over which vars belong to which task.
I have not run this. May wan to change the 1ms time tick to 10ms if Spin can't keep up.
Heater said "Here is an 8 LED cooperative task scheduler example with only one actual LED flasher method with parameters to select which LED and period it should use. The flasher method is now in its own spin file as separate object. That save the confusuion over which vars belong to which task. I have not run this. May wan to change the 1ms time tick to 10ms if Spin can't keep up."
I must say this code is remarkable! However, I ran it "as is" and nothing lights up. Next I will try the 10ms and let you know the results.
Humanoido
humanoido
Each task instance should be sure to only disturb it's own pins direction and state.
So remove the OUTA from the init method and change the DIRA to:
Change the OUTAs in the run method like so:
Do I have to solder some LEDs to my TriBlade Prop #3 ?
The init call for LED 0 does not have bit zero set in the LED parameter, should be:
"I can try another 8. What do you think?"
Now that you have that working it's easily extendable to 16 LEDs:)
I already have the original program working on 10 LEDs now. It goes from P7 on the header to P16 using the LEDs soldered on the demo board. It's a very nice arrangement. I'll continue adding LEDs until I get to 16. After that, I can harvest 4 more ports from the TV circuit for a total of 20 LEDs.
Heater, nice work, so if you were to speculate about how many (maximum) LED threads can run, with either program, what do you think? 128?
No idea. Of course you run out of memory at some point. Or you run out of time, perhaps 1ms is to fine grained.
Actually thinking about time, that 1ms timer tick will drift off depending on the execution time of all the thread run calls. so if one of our tasks was responsible for counting seconds, minutes, hours etc as a real time clock it would soon be wrong.
If we want more accurate timer ticks we should really do something like:
As shown in the propeller manual p74.
With that in place everything goes well until the total execution time of all the task calls exceeds 1ms then the waitcnt will hang up until CNT rolls over, 20 seconds or so.
But you've outgrown this method already. There are only two counters per cog, and you're way past two LEDs. The counters could provide a resettable counting value, but as you're progressing, they really don't offer anything over using the cnt register.
John R.
Humanoido
EDIT:I just remembered a way to double and triple the LEDs using the same number of ports. It's a technique used on BASIC Stamps. So an average of 25 displays can become 50 or 75. That gives some upward mobility..
Consider it done. The new code with a more accurate timebase is up and running!
I knew that would happen at some point. It needs a warning light, a red LED that lights steady to indicate an imminent rollover in the next cycle.
Humanoido
No, when we run out of RAM on the Prop we just virtualize it and continue. Same with LEDs:)
I'm confused...... based on your posts under "more cogs from one prop" and "cloning leds" , are you trying to see how many LED's you can light up with independent (deterministic?) timings, or are you trying to see how many independent threads can be supported under SPIN, and just using the LED's as indicators of that?
Cheers,
Peter (pjv)
Humanoido