Home
JAQForum Ver 20.06
Log In or Join  
Active Topics
Local Time 16:57 09 May 2024 Privacy Policy
Jump to

Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.

Forum Index : Microcontroller and PC projects : Multitasking with MMBasic

     Page 1 of 2    
Author Message
kiiid

Guru

Joined: 11/05/2013
Location: United Kingdom
Posts: 671
Posted: 01:48am 16 Jul 2013
Copy link to clipboard 
Print this post

I am in process of preparing the new 4.4/R5 firmware for the DTX module. It will include native multitasking managed by two new commands in MMBasic - THREAD and PRIORITY (the second one can be executed as function as well to return the current thread priority).

Here are two simple examples to demonstrate:



Thread MyThread1
Thread MyThread2
Thread MyThread3
Thread MyThread4

For p0=1 To 200
Print ".";
Next
End

MyThread1:
For p1=1 To 100
Print "1";
Next
End

MyThread2:
For p2=1 To 50
Print "2";
Next
End

MyThread3:
For p3=1 To 20
Print "3";
Next
End

MyThread4:
For p4=1 To 10
Print "4";
Next
End



This is the result of its execution:

121324.1324.1324.1324.1324.1324.1324.1324.1324.1324.132.132. 132.132.132.132.132.132.132.132.12.12.12.12.12.12.12.12.12.1 2.12.12.12.12.12.12.12.12.12.12.12.12.12.12.12.12.12.12.12.1 .1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1 .1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1...................... ............................................................ ....................

And another example, this time with priorities:



Thread MyThread1
Thread MyThread2

For p0=1 To 200
Print ".";
Next
End

MyThread1:
Priority 5
For p1=1 To 100
Print "1";
Next
End

MyThread2:
Priority 2
For p2=1 To 50
Print "2";
Next
End



And its result:

111112.1121112.1121112.1121112.1121112.1121112.1121112.11211 12.1121112.1121112.1121112.1121112.1121112.1121112.1121112.1 121112.1121112.1121112.1121112.1121112.2222.2222.2222.2222.2 222.2222.2222.2222.2222.2222.2222.2222.22........................................................................................ ............................................................ ....................


I have uploaded a test beta release (sorry, the help file is not ready yet) here: www.dimitech.com/temp/r5beta.zip

Anyone interested may give it a run and let me know any bugs. This firmware with the exception of the RTC will work on any MM-compatible device - MM mono, MM mini and all forks. No DM support in it, sorry.

Enjoy!

Kon
Edited by kiiid 2013-07-17
http://rittle.org

--------------
 
Juri74

Senior Member

Joined: 06/02/2012
Location: Italy
Posts: 162
Posted: 04:06am 16 Jul 2013
Copy link to clipboard 
Print this post

that's a great feature Konstantin!
are the process executed really in parellel? or are something like executed serially.
this function would be great for my project because i've to monitor countinously an input pin, and i've not to miss any pulse..
another question: is it possible to use the same variable in all process?

Continue this great work!
JuriEdited by Juri74 2013-07-17
 
MicroBlocks

Guru

Joined: 12/05/2012
Location: Thailand
Posts: 2209
Posted: 04:59am 16 Jul 2013
Copy link to clipboard 
Print this post

I have mixed feelings about using threads. Even in PC software there is a trend to get away from threads as they often can over complicate a program compared to event driven.

You would need LOCK or MUTEX to make sure variables are not corrupted.
SLEEP to make threads not use valuable processor time.
STOP/START/KILL to be able to stop,start or kill threads.

Multithreading in a single processor structure is accomplished with time slicing.
I guess the only way to do it in BASIC is to switch threads after checking priority when a basic instruction has been executed.

I am more for event driven software as the performance is better and programs are easy to understand and maintain.
If you don't want to miss a pulse on a pin, threads will not help you. An interrupt routine will.

Currently MMBasic has interrupts for PINS, Comports, I2C, CAN, ON KEY and for timing SETTICK. More than enough to make everything event driven.


Microblocks. Build with logic.
 
Dylan
Regular Member

Joined: 17/06/2013
Location: Netherlands
Posts: 81
Posted: 05:55am 16 Jul 2013
Copy link to clipboard 
Print this post

  TZAdvantage said  You would need LOCK or MUTEX to make sure variables are not corrupted.
SLEEP to make threads not use valuable processor time.
STOP/START/KILL to be able to stop,start or kill threads.
...
Currently MMBasic has interrupts for PINS, Comports, I2C, CAN, ON KEY and for timing SETTICK. More than enough to make everything event driven.

I'm willing to guess that he's using interrupts for "threads" too.
 
kiiid

Guru

Joined: 11/05/2013
Location: United Kingdom
Posts: 671
Posted: 01:19pm 16 Jul 2013
Copy link to clipboard 
Print this post

The threads are really in parallel and are sliced at command level. So, what you see is really what you get :)

Now the interesting part - I am not loading the micro with another interrupt. But it doesn't come completely for free. Some RAM is used for the process swapping. Not much, but still...

This is a very early stage and because multitasking is a very fundamental difference from the the single tasking way of thinking, bugs are (very ) possible right now. Also, I will need to figure out how to deal with the blocking commands such as PAUSE, INPUT, etc... For now they stop all the threads, but that might change and let the other threads run even if there is a blocking command on the current one. I haven't tested how a few threads work with files too.

I rather bet on simplicity. If you expect to see a full blown unix or windows style multitasking, this is simply not the case here. So my intent is to stay within the two commands (could be even one without priorities). So, mutex, semaphores and all that stuff - won't happen.

Little bit more details:

A thread is not like a subroutine. It is more like two or more separate programs, each can have its own variables, functions, etc. Or they can be shared as well. Global variables can be shared as well as functions, subroutines and libraries.
The command END effectively ends the thread. The same command remains unchanged when used in the main thread - ends the program with all of its threads at once.

Priority 1 is the lowest. All threads start with it. It means there is no preferred execution and each thread gets exactly the same slice of one command. Increasing the priority gives the thread execution of more commands at once. Priority 0 has the same effect as an END command.

Multitasking is not dangerous as long as you know what to use it for. But it is optional and if not needed, you may wish to stick with single-threaded programs. For embedded purposes though, especially when reading many sensors and pins at once, it allows much better structured programs and optimised execution.

What a thread can't do now is to start, stop or pause another one. I don't see that as a big problem but also don't see any particular benefit from it.
The THREAD command itself only loads the needed parameters in a list and returns immediately to the caller. It can be executed anywhere in a program (i.e. there is a way to get a global variable indicating whether a thread is running or not and run it at will when needed). Things like that...

There is a lot more to test, I just wanted to share the ideas up to this stage and get some feedback from people who wanted to test it as well.
Planning to support CMM's firmware in near future as well although that is not a high priority task on my list.

TZA, there are many things which you can't do with interrupt driven model only. Or can't do in the easy way. I will leave to you to figure them out (believe that won't be a problem for you ;) but the easiest way to demonstrate - write an interrupt driver program which will produce the results above). And again - every new feature is optional and you can simply not use it if not needed.
Edited by kiiid 2013-07-18
http://rittle.org

--------------
 
TinkersALot
Regular Member

Joined: 20/11/2012
Location: United States
Posts: 72
Posted: 05:17pm 16 Jul 2013
Copy link to clipboard 
Print this post

I get a 404 on the zip file link above
 
kiiid

Guru

Joined: 11/05/2013
Location: United Kingdom
Posts: 671
Posted: 05:19pm 16 Jul 2013
Copy link to clipboard 
Print this post

  TinkersALot said   I get a 404 on the zip file link above


That's correct. Sorry, try this link: http://www.dimitech.com/temp/r5beta.zip

Apparently the forum's software requires the http:// part otherwise tries find the link on the internal server.

http://rittle.org

--------------
 
TinkersALot
Regular Member

Joined: 20/11/2012
Location: United States
Posts: 72
Posted: 05:24pm 16 Jul 2013
Copy link to clipboard 
Print this post

  TZAdvantage said  Even in PC software there is a trend to get away from threads as they often can over complicate a program compared to event driven.


Not certain about the complete accuracy of this statement. Even an event loop implies another thread monitoring for events and then percolating them up to some other programming waiting for events. It may be more accurate to say that we've now seen some of the pitfalls associated with (over)threading, and for certain processes, different threading models are the most applicable -- and in some cases, even if that means that a single threaded process is the best design for that problem -- that should not mean that single threads are suitable for all problems.

  TZAdvantage said  You would need LOCK or MUTEX to make sure variables are not corrupted. SLEEP to make threads not use valuable processor time. STOP/START/KILL to be able to stop,start or kill threads.



This is a good point and would be needed for any data read/write that is not atomic (say dumping a few characters into a contiguous buffer). But for atomic read/writes locks may not be needed. But the definition of atomicity does need to be well understood.
 
StoveMan
Regular Member

Joined: 29/03/2013
Location: United States
Posts: 51
Posted: 07:16pm 16 Jul 2013
Copy link to clipboard 
Print this post

kiiid,
Multitasking is better I think for embedded control than event driven division of tasks. What do you do with a process that must respond continuously to input. like a DSP style routine? A PID loop that requires an analog reading as fast as possible? Or a fuzzy logic data set that makes a decision each iteration. Events are great for a single level FSM or waiting for user input, and they definitely have their place; but I always end up with a longer than comfortable main loop with subroutine hell which tries it's best to assign priority anyway.

Let's face it interrupts, well they interrupt the main flow to quickly handle a situation, but are really not suited to anything too intensive. A machine's wheels continue to turn with or without events; so 'event driven programming' is an illusion. For a PC, yeah, we think we have a nice clean program; but somebody is watching the processor temp and controlling the cooling fan speed without any event.

I have programmed the SPLAT boards from AU and they use a virtual machine (interpreter) with multitasking. Their implementation is clean and small.
Here are some of the features of I like:

No priority just a round robin switching... simple and robust.

A task cannot execute more than ~ 256 instructions without yielding...Prevents task stalling.
Task switching using keyword YIELDTASK or when a normally blocking instruction is reached (Pause). A blocking instruction triggers an immediate task switch while continuing to time in the background. SPLAT exploits this with a lot of blocking instructions; I love WAITON(pin). Which just continually yields until the condition is true.

LAUCHTASK, KILLTASK can modify the cue... allows single run code or quiescent code.

Non blocking task switching leads to very modular programming.
I use them to provide "black box" functionality for sensor arrays and motors; and always include a FSM as one task. Once all the core tasks are running there IS no main loop. What results is true event driven programming. All tasks end up waiting for their respective data and then operating on it. Maybe the down side is multi-instancing not multitasking.

Timing can be somewhat tricky in threads. A global tick timer which can be read by all tasks works; as well as the RTC.
Variable use is no harder in threads than multiple interrupts and dozens of Subs. I just prefix all variables with a mnemonic to identify who owns it.
When a task OPENS a file or port it owns the resource and an error will be raised if any riff-raff encroach.

Keep up the work on this kiiid, only way to go for embedded!
Frank
 
vasi

Guru

Joined: 23/03/2007
Location: Romania
Posts: 1697
Posted: 11:50am 18 Jul 2013
Copy link to clipboard 
Print this post

freeRTOS from ATMEL perspective - a nice presentation
http://www.youtube.com/watch?v=By8Q7UjPqnI
Hobbit name: Togo Toadfoot of Frogmorton
Elvish name: Mablung Miriel
Beyound Arduino Lang
 
MicroBlocks

Guru

Joined: 12/05/2012
Location: Thailand
Posts: 2209
Posted: 08:48pm 18 Jul 2013
Copy link to clipboard 
Print this post

Kon,

It is not that i don't see merit in multitasking, it is more the incomplete implementation of it that is my concern.
The biggest pitfall is the corruption of variables.
With some effort it can be easily prevented.
Read the following as a comparison with how i would make it if i had the time.
If there is something in it that you like all the better. :)

To take a little part of your example:

[code]
MyThread1:
Priority 5
For p1=1 To 100
Print "1";
Next
End
[/code]

it would be cleaner if it can be written using a defined subroutine or function.

[code]
Function MyRoutine()
Local p
For p=1 To 100
Print "1";
Next
End Function
[/code]
The advantage is local variables. This will make reusing code a lot easier and will facilitate the new library functionality.

I would even go so far to use a TASK keyword
Like this:
[code]
TASK MyRoutine()
Local p
For p=1 To 100
Print "1";
Next
END TASK
[/code]
Starting the task can then be done with RUNTASK MyRoutine, 5. Or you can choose to start the task immediately.
As it uses exactly the same structure of a Function i think it would be not too difficult to implement.
With LOCAL the use of global variables is reduced but still you need a good way to use them.

For global variables unfortunately there are two ways of using them.
1 ) Each task uses their own and the programmer has to do the administrative task of making sure they are not being updated by more tasks. Very simple application can use this. Note that making library functions, especially ones that have inter communication are getting increasingly vulnerable for very elusive bugs. And with an interpreted language your chance of finding those bugs is very difficult as it only occurs at runtime and there is no debugger.

2 ) Once an application gets bigger there is unfortunately no other way then locking the global variable.

The easiest way would be to add a flag (one bit in the variable table) to signal that it is locked.
The basic syntax could be:
[code]
A=1

TASK MyRoutine()
LOCAL Index, Temp

FOR Index = 1 TO 1000
LOCK A
IF A < 100 then A = A + Index
END LOCK
NEXT

END TASK
[/code]

The LOCK A then sets the flag on the "A" variable so that if another task wants access to it it has to wait. The END LOCK resets the flag and allows the other waiting threads to proceed.

You then have a basic structure that can be build upon with more functionality.
The LOCK command for instance can be expanded to include Files, COM ports and PINS.
A nice path for upgrades.

[quote]
I rather bet on simplicity. If you expect to see a full blown unix or windows style multitasking, this is simply not the case here. So my intent is to stay within the two commands (could be even one without priorities). So, mutex, semaphores and all that stuff - won't happen.
[/quote]
(Emphasize mine)
No need for full blown multitasking, just a locking mechanism.
As a programmer i don't like to be able to only write simple stuff. The intricate, difficult stuff is where the opportunities are. And if the language does not support locking it has to be written using basic instruction.
That gets tiresome and buggy very quick not to mention that some things can just not be done using basic statements alone.

And to stress the point even more, even the simple stuff gets much simpler when locks are supported.

If you make a hardware module that does a specific job you can write a library routine for it in the form of a TASK. This would increase sales of modules.

If you allow parameters in the TASK definition (same as with a function) you can pass references to variables in it.

Lets assume you have a temperature sensor module. You can then write a TASK that reads that temperature and store the result in a variable.
The user program then only has to read that variable to get a temperature reading without having to program the I2C, SPI, 1-wire or whatever interface is used.
Just load the TASK in memory with the library function, start the task and your done.
like this:
[code]
Temperature = 0

TASK TemperatureTask(Temperature),10

'Main program
DO
Print "Temperature =" Temperature
PAUSE 1000
LOOP

'The task that is loaded previously or included in the source
TASK TemperatureTask(value)
'This example will get the temperature every 0.1 second
DO
'Read the temperature from the device
'with code specific for the device
'SPI, I2C, 1-WIRE, Analogue port etc..
'Sets the referenced variable with the new temperature reading
Value = TemperatureFromDevice
PAUSE 100
LOOP
END TASK
[/code]
Especially notice the use of PAUSE that is necessary when using threads.
In MMBasic PAUSE is blocking making the above impossible.
You would then need a SLEEP that is only blocking in the thread that uses it.


In my own 'Blox' series i am doing it like this:
[code]

Function BLOX_TMP4X(temp1, temp2, temp3, temp4)
LOCAL Temp[3]
'Read temperature from the temperature sensor blox TMP4X
'use I2C to get the values in an array
temp1 = Temp[0]
temp2 = Temp[1]
temp3 = Temp[2]
temp4 = Temp[3]
End Function
[/code]

I have a dispatcher routine template that uses one SETTICK timer to act as a timeslicer.

[code]
'Global variables to hold temperatures
BedTemp = 0
Extruder1Temp
Extruder2Temp
ChamberTemp

TimeSlice = 0
SETTICK DisPatcher, 100

SUB DisPatcher()
TimeSlice = TimeSlice + 1
If TimeSlice = 100 then TimeSlice = 0
IF TimeSlice MOD 10 = 0 then
BLOX_TMP4X(BedTemp, Extruder1Temp, Extruder2Temp, ChamberTemp)
DisplayGraph()
ENDIF
END SUB
[/code]

Notice that PAUSE is not being used.
The smallest Atomic action is a function or subroutine. The need to be small and quick.

Your threads/tasks addition smallest atomic action is a basic instruction. This allows finer grained tasks, which is good, but needs locking facilities to unburden the programmer of the task to administrate variable use.Edited by TZAdvantage 2013-07-20
Microblocks. Build with logic.
 
kiiid

Guru

Joined: 11/05/2013
Location: United Kingdom
Posts: 671
Posted: 09:22pm 18 Jul 2013
Copy link to clipboard 
Print this post

TZA, locking is needed if the multitasking is done on ticking interrupt principle and it runs under the interpreter. The way I have done it is not that way and there no way that a variable will get corrupted unless you intentionally change its value from another task. Probably your previous post would have been a bit more substantiated if you had tried the hex which I posted and demonstrated your concerns in practical examples with it.
As I said I bet on simplicity and this set of two commands is the minimum needed to do effective multitasking. Everything more than this creates redundancy and less than 100% practical benefit.
In your examples - if you like structuring your code in small functions, there is nothing stopping you to do that now. Functions can also work as separate threads.
You can do start/stop by using global variable as a flag, you don't need variable locking because of the way it works. You can dynamically change priority during the task to create exclusive execution.
For more advanced multitasking probably dedicated OS-es would provide better options, but that is out of my area of interests.
Thanks for the suggestions anyway, there is always way for improvement and I will keep working on this...Edited by kiiid 2013-07-20
http://rittle.org

--------------
 
TinkersALot
Regular Member

Joined: 20/11/2012
Location: United States
Posts: 72
Posted: 03:55am 19 Jul 2013
Copy link to clipboard 
Print this post

  TZAdvantage said   ...You then have a basic structure that can be build upon with more functionality. The LOCK command for instance can be expanded to include Files, COM ports and PINS. A nice path for upgrades....


This is an excellent observation. completely concur.
 
cwilt
Senior Member

Joined: 20/03/2012
Location: United States
Posts: 147
Posted: 04:12am 19 Jul 2013
Copy link to clipboard 
Print this post

kiid,

I like the multitasking idea I am just not sure where I would use it instead of interrupts.

For example, I created a simple http server using a wifly. I configure the alternate use of the IO pins on the wifly so that when a client connects it causes and interrupt to fire on CMM and parse the http request and return the requested information.

In a situation like this is there a way to make use of multitasking? I think a thread would take the place of the interrupt, which is fine, but which is faster?

 
MicroBlocks

Guru

Joined: 12/05/2012
Location: Thailand
Posts: 2209
Posted: 05:32am 19 Jul 2013
Copy link to clipboard 
Print this post

cwilt,

Normally you would use an interrupt to respond as quickly as possible to a request.
In the interrupt routine you just queue the request, nothing more.
A task (can be the main program) will just poll the queue if there is any work to do and if a 'job' is in the queue it takes it from the queue and processes it by building a 'response' and send it to the socket the request was received on.
This will ensure you are not missing any requests.

You might want to read about IOCP to get some theory (it is for PC's but the same principle applies), It be overkill if you are sure that request will be coming in one by one.
Realize that a webpage with style sheet, javascript, pictures etc on it will fire requests very rapidly, one for each resource.

Microblocks. Build with logic.
 
Grogster

Admin Group

Joined: 31/12/2012
Location: New Zealand
Posts: 9072
Posted: 01:34pm 19 Jul 2013
Copy link to clipboard 
Print this post

  TZAdvantage said  Normally you would use an interrupt to respond as quickly as possible to a request.In the interrupt routine you just queue the request, nothing more.
A task (can be the main program) will just poll the queue if there is any work to do and if a 'job' is in the queue it takes it from the queue and processes it by building a 'response' and send it to the socket the request was received on.
This will ensure you are not missing any requests.


TOTALLY agree with that.

In my ORIGINAL experiments with interrupts, I had the whole interrupt processing routine inside the interrupt - seemed like a good idea at the time - interrupt happens, and runs this code here to do what I need.

Was pointed out in the manual and by others here, that interrupts should be as short as possible, and with all the processing code inside the interrupt, during testing, I WAS missing new incoming messages(my interrupt was on the serial port).

With the advise of the forum, and admitting that the manual was indeed right, I rewrote the interrupt to just suck the message in off the com port, and plonk it in a string, then IRETURN. That done, the main loop now looks at the length of the string, and if it is longer then one character, then the loop knows it needs to process something. Once that processing has happened, the last command before leaving that routine, is to clear the string with the likes of A$="". Perhaps not the best code in the world, and still needs more work for code efficiency, but definitely a step up from what I had originally, and now so long as I don't get more then two messages within a second or so of each other, everything is working fine.

With the new version of MMBASIC, I plan to use an array to store my incoming data(probably 10 elements as a starting point), as the latest version supports specifying how much RAM to use for each element in an array, instead of the default 255 bytes.(i only need 21 bytes per element, so an array will work really well like this for storing the incoming data and also not gobbling up heaps of RAM, now that I can tell the MM how many bytes to use for each array element.)
Edited by Grogster 2013-07-20
Smoke makes things work. When the smoke gets out, it stops!
 
kiiid

Guru

Joined: 11/05/2013
Location: United Kingdom
Posts: 671
Posted: 01:52pm 19 Jul 2013
Copy link to clipboard 
Print this post

  cwilt said   but which is faster?



Neither is faster or slower. They are different and used in different situations, often complementary one to the other. It is like comparing which one is faster - a car or a cruise ship? One will take 100km distance in 1 hour but with five people on board while the other will take it in 6 hours with 1000 people on board.

In an average program your main loop would normally look like something like this:

MAIN:
check_something
check_something_else
check_something_much_more_else
do_something
do_something_else
GOTO MAIN

What is the execution speed in a single iteration naming the execution speed of a single BASCI command as one?
It will be C1+C2+C3+C4+C5 where Cx will be the number of executed BASCI commands within each of your functions. Now imagine C2 is a large number i.e. there are heavy calculations or many things to do. Your WHOLE program will run much slower because of the speed of a single procedure.
Even if you go the extra mile and split every function into smaller ones, the overall execution speed will still be slower because of the extra conditional checks you will need to perform. There are many case where that is even impossible.

With multitasking without priorities the speed above will be always exactly 5. No matter how complex each of your functions is, the execution speed will never change.

Not long ago I had to write the firmware for an automotive datalogger. You have many tasks running in parallel there and delaying even one of them is not an option as it will slug the whole thing. There is absolutely no workaround for multitasking in such cases. In other hand for simple and short programs you may never experience the need for it.

Now, interrupts are different thing - if you need to react quickly on some event, you don't poll for it but expect it within an interrupt. Interrupts are (almost) exclusively single thread procedures, because they must return the execution back to the main body as soon as possible. Some thing can't be done in other way than interrupt.

So in short - interrupts and multitasking are different things and should not be mixed in comparison.


http://rittle.org

--------------
 
cwilt
Senior Member

Joined: 20/03/2012
Location: United States
Posts: 147
Posted: 03:01pm 19 Jul 2013
Copy link to clipboard 
Print this post

  TZAdvantage said   cwilt,

Normally you would use an interrupt to respond as quickly as possible to a request.
In the interrupt routine you just queue the request, nothing more.
A task (can be the main program) will just poll the queue if there is any work to do and if a 'job' is in the queue it takes it from the queue and processes it by building a 'response' and send it to the socket the request was received on.
This will ensure you are not missing any requests.

You might want to read about IOCP to get some theory (it is for PC's but the same principle applies), It be overkill if you are sure that request will be coming in one by one.
Realize that a webpage with style sheet, javascript, pictures etc on it will fire requests very rapidly, one for each resource.


How quick that interrupt responds depends on where the interrupt handler lives. If the interrupt handler is written in C and closer to the hardware then it will be faster than a software based handler operating on top of mmbasic. I do believe mmbasic interrupts are software based, not hardware.

On the other hand I remember kiid saying that his multi-tasking routines were written in C and compiled in. If that is the case it should be operating closer to the hardware layer and may actually respond faster.

My web server is simple and handles only basic html with get and put.
 
MicroBlocks

Guru

Joined: 12/05/2012
Location: Thailand
Posts: 2209
Posted: 08:31pm 19 Jul 2013
Copy link to clipboard 
Print this post

Interrupts in MMBasic are slow compared to ones in C. Even if they are real interrupts and not polled before they end up in the higher level language at least the current basic statement has to be completed. So you have a delay, which can be too much depending on the use.
You do not need to count cycles with an interrupt, you can define a pin as a "count input" that does that for you. Or even a "frequency input" if it is a real fast signal.

Which one is faster?
If you mean which responds faster, it is the interrupt. Response time is also within a very small margin.
A taskswitcher can respond very quickly or very slowly depending on when the polling task gets its time slice and where in the polling loop the task is. The response time can vary wildly.
Above is when you use C or assembly.

In MMBasic there are no real interrupts, so the fastest time an interrupt can be handled is after the current basic instruction is finished. This will give a reasonable margin.
With task switching it again depends where in the polling loop the task is and also which priority it is running. The fastest possible will be the same time as the interrupt, the slowest is at least three times as much and slows done with the number of tasks.
Both the task and interrupt can not process it,because a next interrupt will be missed or the task will miss the poll.

In short. Interrupts are faster and more consistent.

Processing it however is a different story.
When only using interrupts and MMBasic as it is now you will spend time processing and that can delay other parts of the program. This is solved by using multitasking, or by other forms of timeslicing like timer events.

Multitasking is fine grained so that other tasks will run at the same speed all the time, the cost is that the processing of the 'interrupt' will take longer as it gets less processing time.

Event driven steals time from other tasks and uses all that time for processing the 'interrupt'.
It depends on the application which one is better. As a small example, when one of your tasks is waiting for a keypress that task will slow done everything.
With events you just do an ON KEY and it will not slow down.

The simplest and most consistent is to mix interrupts, events, and tasks.
For the 'webserver' i would use an interrupt to catch and queue the request and a running task to process it.
The best would be to use interrupts to catch real world events and use tasks for processing. Because interrupt driven and tasks are not good at both.
Never use interrupts that includes processing and try not to use tasks for polling.
Edited by TZAdvantage 2013-07-21
Microblocks. Build with logic.
 
vasi

Guru

Joined: 23/03/2007
Location: Romania
Posts: 1697
Posted: 01:56am 20 Jul 2013
Copy link to clipboard 
Print this post

I guess you'll have to drop the VGA feature for a reliable real time MMBasic which is fine by me (the console is enough). If that is reliable enough for industrial real-time applications imagine the impact...
Hobbit name: Togo Toadfoot of Frogmorton
Elvish name: Mablung Miriel
Beyound Arduino Lang
 
     Page 1 of 2    
Print this page
© JAQ Software 2024