![]() |
Forum Index : Microcontroller and PC projects : MM feature request
Page 1 of 2 ![]() ![]() |
|||||
Author | Message | ||||
Volhout Guru ![]() Joined: 05/03/2018 Location: NetherlandsPosts: 5089 |
@Geoff, Matherp, I've been working with Arduino, MicroMite (and Maximite) and Picaxe for years. But only recently I discovered that the PICAXE can do multitasking. I was working on a (more or less real time) control function, and had to add human controls (keys, leds, display). I decided for the first time to use multitasking (this picaxe (18M2) knows up to 4 tasks). And it worked wonderfull. Even when I added delays for key debounce in the keyboard scan task, the fast main control loop did not show any iregularities (well...minor ones...). I know Micromite basic can achieve similar functionality since it can work with interrupts, and interrupts on timers, but it is not quite as simple as having multitasking. MMbasic is also far more powerfull, so it is possible this cannot be implemented easily. I am posting this since I was stunned by the fact that it was soo simple to abstract functions without having to worry about real time issues. It would be great if MMbasic could offer such comfort. as far as I understand on picaxe multitasking - the picaxe interpreter switches tasks the moment it finalizes one basic command, so the task switching is depending on the complexity of the command, and the time it takes to execute. - there are excemptions for some commands: timed delays, RS232 communication (buffers?). It is documented that timed delays become more inaccurate. - tasks can be started, suspended, resumed, and restarted - the picaxe does not support local variables. all is global. Can MMbasic become MMMbasic ? (MicroMiteMultitasking).... Volhout PicomiteVGA PETSCII ROBOTS |
||||
viscomjim Guru ![]() Joined: 08/01/2014 Location: United StatesPosts: 925 |
I am not really familiar with picaxe, but the 18M2 is just an 8 bit 16F1847 with a single core running at a max speed of 32mhz, so I don't know how they are doing parallel processing. The only way I can image this working is using a "state machine" type of way. I have used THIS type of logic with the timer function on the MM before and this "simulates" multi tasking using different timed intervals to switch between different operations. This method may be the way picaxe is doing it "behind the scenes"? Not sure, but a theory. This can also be done with MMbasic. Of couse, MM can also process interrupts and handle serial comms, PWM, etc. while continuing to run the main program. |
||||
Geoffg![]() Guru ![]() Joined: 06/06/2011 Location: AustraliaPosts: 3292 |
Aaaggghhh!! That is quite a feature. It is not possible on the 28 and 44-pin Micromites (not enough flash) but I will think about it for the MM+. Multitasking is not easy, for example, what if two different tasks are trying to execute the same loop at the same time? Then you need interprocess communications (semaphores, etc), wait on events, etc... not easy. I am guessing that the PICAXE implements a very limited version of multitasking. That would be easier, For example, it would be easy to simply have four program pointers and switch between them in round robin style and leave the BASIC programmer to figure out the issues. But would it be really useful? Hmmm... Geoff Graham - http://geoffg.net |
||||
JohnS Guru ![]() Joined: 18/11/2011 Location: United KingdomPosts: 4044 |
No doubt it would be useful. It will also simplify some programming needs and the code. Without proper semaphores etc sooner or later various people will hit bugs that will be "hard" to find, until they grasp why those things are needed. With semaphores etc sooner or later someone will rediscover deadlocks. Still, sounds worth adding. Good luck with suitable warnings or just provide URLs to articles about semaphores etc. You're likely to need one (MMBasic) stack per task but with enough extra RAM that's just a detail. Quite which task you take an interrupt in may be interesting especially if it's whichever one happens to be active i.e. it varies... John |
||||
CaptainBoing![]() Guru ![]() Joined: 07/09/2016 Location: United KingdomPosts: 2170 |
I suspect the multi-tasking isn't really as it won't be event driven with the processor sitting parked (i.e. halted) and only bursting into life when something comes along. You still have a loop of some sort executing. Happy to be wrong. There may be time-slicing (which is just about the only way to do it with a single core) but even then the processes are not truly running simultaneously, it's just switching rapidly between different sections of code... did a similar thing on a bespoke Z80 kernel back end of the 80's. Unless the tasks are doing something where there is a lot of waiting involved (like serial I/O) then the two tasks will take the same time to run sequentially as in parallel (actually a bit longer as there is switching overhead). Again, happy to be wrong. If you have an immediate need, consider state machine methodology. This way you have a lean main loop that just services flags/pins and calls separate subs to do the work (bonus: it makes it a doddle to debug your stuff). When done well (by which I mean don't be tempted to make your service/main loop do anything except service your stimuli), it can end up "looking" like m/t quite convincingly. As an example; at a very low level, proper serial I/O routines do this by not waiting for characters to go before sending the next one (I #*%$! hate code like that). They load a register then either poll or get interrupted by a flag saying "ready for the next". You call the sub to load the next char from the buffer. If you consider a 9600 baud link can take a milli-second per character - if you are just waiting around that is a massive waste of compute. my 2p |
||||
Volhout Guru ![]() Joined: 05/03/2018 Location: NetherlandsPosts: 5089 |
@JohnS, Yes, you definitely need semaphores in your basic code. If you are altering data in one task, you need a flag (semaphore) to indicate new data is available, since the other task could use invalid data (worst case: while the data is being changed, so it is neither old nor new). So the one who writes the code must be aware of that. In my case it was very straightforward: the keyboard task set's a semaphore when it has a a new key, the main task clears the semaphore when it accepts the key. But imagine how you would do this same piece of code in a "linear" basic program. Matrix scanning a keyboard with deboucing -and- a control loop for a PID. You would almost have to integrate the keyboard scan into the control loop. Or a pretty complex timed interrupt routine...for the PID algorythm (because the PID is more time critical than the keyboard scan). No doubt the interpreter also needs semaphores, and probably every task needs it's own stack. But it could very well be that they use exctly what Geoff hinted. A program pointer list that the interpreter cycles through. PicomiteVGA PETSCII ROBOTS |
||||
JohnS Guru ![]() Joined: 18/11/2011 Location: United KingdomPosts: 4044 |
You just use a state machine along the lines of ones which people have even posted from time to time. John |
||||
lizby Guru ![]() Joined: 17/05/2016 Location: United StatesPosts: 3378 |
This is basically what the picaxe "multi-tasking" does. Nothing is parallel; the multiple tasks are executed round robin style. The 18M2 has multiple "slots" which may have separate programs (with shared variables). I'm not sure whether a slot gets to execute for a certain period of time or one command at a time before the next slot program pointer is used. PicoMite, Armmite F4, SensorKits, MMBasic Hardware, Games, etc. on fruitoftheshed |
||||
Volhout Guru ![]() Joined: 05/03/2018 Location: NetherlandsPosts: 5089 |
Hi JohnS, Always happy to learn about state machines, so please explain. Let's assume we want to generate a 50Hz square wave that we can stop and start with 2 buttons. This is more or less exactly the picbasic code. I know MMBasic has PWM's that can handle it, so has the picaxe, this is just to explain how simple it is to abstract two processes. Would be a lot harder in a state machine I guess. start0 do if stop=1 then out=low else out=low delay 10 out=high delay 10 end if loop start1 do if stopkey=1 then stop=1 do delay 50 loop until stopkey=0 if startkey=1 then stop=0 do delay 50 loop until startkey=0 delay 50 loop This code is not documented, but it is not very difficult to understand. Happy to explain if required. By some stupid reason the indenting disappeared.... PicomiteVGA PETSCII ROBOTS |
||||
JohnS Guru ![]() Joined: 18/11/2011 Location: United KingdomPosts: 4044 |
OK, so I used google and about the first thing it got was this Or for the general idea this A multi-tasking MMBasic will obviously run somewhat slower and use more RAM but on the bigger CPUs those wont matter. Clearly up to Geoff to decide what he wants and feels is appropriate. Quite a lot of the internals will need rewrites but many are trivial. (On the basis this is pseudo-multi-tasking i.e. one thread switched across multiple tasks, rather than using a multi-CPU and a thread per CPU. I don't think there's a rush to go the whole hog.) John |
||||
MicroBlocks![]() Guru ![]() Joined: 12/05/2012 Location: ThailandPosts: 2209 |
I go around all of it by using events with timer ticks and interrupts. Sure it is not multitasking but it comes close enough. Timings should never be done by using delays but rather with timer ticks. Simplest form is to update a counter each time a timer tick happens, and with each value of that counter call a specific function. You can then have one to hundreds of "tasks" depending on your needs. Microblocks. Build with logic. |
||||
CaptainBoing![]() Guru ![]() Joined: 07/09/2016 Location: United KingdomPosts: 2170 |
@Volhout for the problem you have, the state machine would look something like the below... note how the main loop does nothing but respond to stimuli. SUBs become true sub-programs and are responsible for the work... everything communicates with everything else by setting flags (semaphores) or some other stimulus. Main: Do If Button1 Then OutputStart If Button2 Then OutputStop Loop Sub OutPutStart PWM 1, 50, 50 ' Freq=50Hz, 1A=50% End Sub Sub OutputStop PWM 1, STOP End Sub The temptation to look at the above is to ask "why no just put the 'active' bits of the code in the If statements?" - that is a factor of the simplicity of the task. What the FSM approach does is apply a container approach...even the above is not strictly FSM - a better version would be... (also notice also the order you put the flag processing decides also the priority - if you hold both buttons down the process is stopped) Main: Do If Button1 Then Flag=1 If Button2 Then Flag=0 If Flag=1 Then OutputStart If Flag=0 Then OutputStop Loop Sub OutPutStart PWM 1, 50, 50 ' Freq=50Hz, 1A=50% End Sub Sub OutputStop PWM 1, STOP End Sub The reason being that any part of your code can start or stop the output simply by setting the flag. The button press (and it's detection) serve only to set the flag... anything could conceivably set that flag, not just a button... a character received on the serial port, another Sub... and it all gets handled by the main loop - nothing is allowed to call an "active" piece of code apart from the main loop - if you want something doing, you have to set the semaphore and let the service loop deal with it. I do this all the time, Here's a section of code from one of my projects which uses the service loop to switch the external hardware. I do this because it suits - the early section of the loop checks for messages in a serial comms channel and processes the flags, the latter part acts on them: ... Case "U" 'door up q$= "Answering Door Up" DoorUpRequest IntLightSetAuto ExtLightSetAuto ... and the associated subs... Sub DoorUpRequest If (FlagTest(DoorUp)=0) And (FlagTest(DoorUpMoving)=0) Then 'if we are not already moving UP Release FlagSet DoorUpMoving After DoorMovePeriod,DoorMoveTimer Else q$= "Ignored (flags)" Endif End Sub Sub IntLightSetAuto FlagRes IntLightON FlagRes IntLightOFF FlagSet IntLightAUTO FlagRes ExtLightFLASH End Sub Sub ExtLightSetAuto FlagRes ExtLightOR If FlagTest(DoorDown) Then FlagRes ExtLightONEnable FlagSet ExtLightOFF Else FlagRes ExtLightOFF FlagSet ExtLightONEnable EndIf End Sub ... and then in the main/service loop... just one, bit... 'process states 'door moving states If FlagTest(DoorUpMoving) Then Pin(DoorUp)=DoorActive EndIf notice how none of the subs do anything but set semaphores for each other. Only the main loop does anything "active" - like actually switching things on or off This might all look a bit long winded but it pays dividends because as you add functionality to a larger project, you write the sub that does the logic (and sets the flags to communicate with other sections of your prog) and it doesn't knock anything else out of place. Then you only have to test a single flag in Main to decide if you have to do something. and no Spaghetti code! all in nice neat little piles. The approach might not suit small projects but I find it is worth the effort because even little jobs tend to grow organically and if you follow this method, all you have to do is write the sub and then process a flag to trigger it. Also I would recommend you have flags for every state i.e. a separate flag for on and another for off - I like to deal with absolutes but it doesn't suit everyone. |
||||
vegipete![]() Guru ![]() Joined: 29/01/2013 Location: CanadaPosts: 1132 |
Years ago I did some programming on a Rabbit processor (sort of Z80ish) using Dynamic C. This variation of C had a sort of multi-tasking built in. I found the user's manual multi-tasking chapter here which might offer some ideas or suggestions. Visit Vegipete's *Mite Library for cool programs. |
||||
JohnS Guru ![]() Joined: 18/11/2011 Location: United KingdomPosts: 4044 |
Given the choice I'd always use multiple tasks rather than a state machine and so in the past have more than once put together a small OS - small enough to be handy but quick to write. However, whereas I'm a full-time software guy, the attraction of BASIC is that it can be used by just about anyone. So, if it gets multi-tasking it probably ought to be something simple to understand. No doubt Geoff can do such a thing if he wishes. John |
||||
Volhout Guru ![]() Joined: 05/03/2018 Location: NetherlandsPosts: 5089 |
All, Previous post contained something that looks like picaxe code, but was I could remember doind while riding a train and typin on a mobile phone. This is working code (just for completeness). I think it got some people thinking. I do understand stete machines a bit better now, so will try to master it. But simplicity.... ' symbol declaration symbol bStop = b0 symbol bOut = B.0 symbol bStopKey = pinB.1 symbol bStartKey = pinB.2 ' task 0 : generate 50Hz square wave ' or do other real time stuff start0: do if bStop=1 then low bOut else low bOut pause 10 high bOut pause 10 end if loop ' task 1 : completely unrelated check keys ' debounce (blocking) without affecting task 0 start1: do if bStopKey=1 then bStop=1 do pause 50 loop until bStopKey=0 end if if bStartKey=1 then bStop=0 do pause 50 loop until bStartKey=0 end if pause 50 loop imagine writing code for a game..... start0: do play music loop start1: do check_for_collisions loop start2: do read keyboard or game paddle loop start3: do process movements update screen loop PicomiteVGA PETSCII ROBOTS |
||||
CircuitGizmos![]() Guru ![]() Joined: 08/09/2011 Location: United StatesPosts: 1427 |
I personally think that with good programming practices and skill "multitasking" is already in MMBasic. I can't imagine the bugs that this might introduce. Micromites and Maximites! - Beginning Maximite |
||||
Grogster![]() Admin Group ![]() Joined: 31/12/2012 Location: New ZealandPosts: 9610 |
Interesting idea. Those for it will always have plenty of reasons why it should be included, and those against will have similar reasons - you can't win. ![]() I do have to kinda agree with CG above though. The OP mentions the PICAXE using a slot to do the keypad thing. Well, that is easy-peasy to do in MMBASIC via the KEYPAD command interrupt. It will scan the keypad matrix in the background and generate an interrupt whenever a key is pressed. All you have to do in the interrupt, is read the value of the key and return from the interrupt - all pretty quick and seamless, and certainly no need to scan the matrix within your main loop or anything. I am certainly not an expert coder, so there may be things I am perhaps not seeing in my interpretation of things. Smoke makes things work. When the smoke gets out, it stops! |
||||
JohnL Senior Member ![]() Joined: 10/01/2014 Location: SeychellesPosts: 128 |
https://www.freertos.org/ Free rtos has been around for ages and is very mature and solid, does not need much overhead, obviously will not fit in small micromites. Used by heaps of other microcontroller platforms. If I was Geoff I would have considered splitting MMbasic into separate underlying OS, doing all the hardware and system servicing, then Basic interpreter on top as a programming language. This may mean starting with clean sheet of paper, but if done correctly would offer more flexibility and other possibilities. |
||||
flip Senior Member ![]() Joined: 18/07/2016 Location: AustraliaPosts: 114 |
I posted a simple multi-tasking program back in Simple Multi-Tasker It's just a demo and very rough and slow...you can tab between windows, type text in them and press Function keys along bottom of screen to start scroller...have since made improvements but no means ready for posting... regards Phil |
||||
JohnS Guru ![]() Joined: 18/11/2011 Location: United KingdomPosts: 4044 |
Something as simple as multi-tasking doesn't need an entire OS. Though it could also be a way to get semaphores etc. And some more things like task with different priorities. It's possible to argue that the existing interrupt features can (and sometimes do) get people into trouble so maybe it would be better to multi-task. At some point it stops being a simple easily understood variant of Basic I expect. (Maybe it stopped already?) John |
||||
Page 1 of 2 ![]() ![]() |
![]() |
![]() |
The Back Shed's forum code is written, and hosted, in Australia. | © JAQ Software 2025 |