Home
JAQForum Ver 24.01
Log In or Join  
Active Topics
Local Time 00:38 14 Nov 2025 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 : MMBasic v4.5 - how to pause/restart tick and share main/isr variables

     Page 1 of 2    
Author Message
flasherror
Senior Member

Joined: 07/01/2019
Location: United States
Posts: 159
Posted: 08:56pm 06 Jun 2020
Copy link to clipboard 
Print this post

MMBasic v4.5 / Duinomite Mega

2 sitations that I'd like to know how others handle:

1. MMBasic has the SETTICK command which can be used to implement a periodic Interrupt Service Routine (ISR) as might be done in C or assembly.
Description from MMBasic ref manual is:

SETTICK period, target [, nbr]
This will setup a periodic interrupt (or “tick”).
Four tick timers are available ('nbr' = 1, 2, 3 or 4). 'nbr' is optional and if
not specified timer number 1 will be used.
The time between interrupts is ‘period’ milliseconds and ‘target' is the
line number or label of the interrupt routine. See also IRETURN to
return from the interrupt. A subroutine can also be specified for the
interrupt target and in that case return is via EXIT SUB or END SUB.
The period can range from 1 to 2147483647 mSec (about 24 days).
These interrupts can be disabled by setting ‘period’ to zero
(ie, SETTICK 0, 0, 3 will disable tick timer number 3).


My question is: how would you temporarily halt the tick without affecting its internal count and restart it?
If you do SETTICK 0, 0, 3 then I believe that you disable the tick and erase its internal count. If you then SETTICK 100, T3_ISR, 3 then you are reinitializing the timer and the tick does not continue count from its previous internal count but starts a new 100mS interrupt timing cycle.

I guess one way of handling this is to use a semaphore (flag variable) to control whether the code in the T1_ISR executes by using a flag like:
T3_ISR:
if T3_enabled = 1 then
' do stuff
endif
ireturn


which leads me to my next question:

2. How to disable "tick" code from executing while you modify internal variables that may be shared between main code and the tick ISR code?
In assembly you'd do a "disable global interrupts" instruction to ensure that no interrupts can run while you are examining/modifying shared variables.
How would you do the same thing in MMBasic?

Thanks
 
panky

Guru

Joined: 02/10/2012
Location: Australia
Posts: 1116
Posted: 04:05am 07 Jun 2020
Copy link to clipboard 
Print this post

@flasherror

Re your question 1, I can not see any way to achieve what you need here, sorry. Holding the settick counter from incrementing while in another set tick interrupt sort of defeats the purpose of a periodic tick.

Re question 2, as far as I know, there is no way of directly disabling all interrupts. My suggestion would be to have a flag, say GlobalIntDisable = 1, which you would include as the first statement in all interrupt service routines and then as the very last line in your ISR, GlobalIntDisable = 0.

In your mainline program, before changing any variable that is embedded in an interrupt service routine, you would check to see if you were inside an interrupt or not by testing the flag. Nested interrupts may get messy however without further flags.

Not overly elegant but it may do what you need.

Hope this helps,
panky
... almost all of the Maximites, the MicromMites, the MM Extremes, the ArmMites, the PicoMite and loving it!
 
KeepIS

Guru

Joined: 13/10/2014
Location: Australia
Posts: 1955
Posted: 04:29am 07 Jun 2020
Copy link to clipboard 
Print this post

I'm looking at your question slightly differently than Panky, however more information might be helpful.

The first thing that comes to mind with not wanting to stop / start a Tick ISR.

Tick interrupts are right at the bottom of the pile as far as interrupt request priority goes, and the priory is then from 1 to 4 for the tick interrupts.  

You could possibly use this to your advantage, as all other interrupts are disabled within the current interrupt. Using a higher tick interrupt to change the variables of the lower priority interrupt, but this still leaves the problem of accounting for interrupting at the correct time and allowing for internal MM Basic overheads that might throw you off.  

The problem with wanting to keep the tick period repeating (without stopping and starting) or even using a flag, is that its timing would still be variable and dependent on a number of higher priority interrupts and delays in code execution in those interrupts, assuming your using some like CFunctions, Touch, Key input, I2C, Serial Communications, GUI and IO interrupts as all have higher priority.

Mike.
Edited 2020-06-07 14:30 by KeepIS
NANO Inverter: Full download - Only Hex Ver 8.1Ks
 
goc30

Guru

Joined: 12/04/2017
Location: France
Posts: 435
Posted: 04:57am 07 Jun 2020
Copy link to clipboard 
Print this post

hi flasherror

Another solution is to use the RTOS (Real time Operating system) methodoligy

when a task is likely to be too long in execution and therefore risks losing basic data, it must be cut into 2 parts:
first task which works under interruption, and which only recovers the basic data and stores them as is in a FIFO stack. This task should be as short and as quick as possible.

And a second task integrated in the main loop, which recovers the data stored in the stack and processes it.

this allows you to never lose data, while processing it in the background.
Edited 2020-06-07 15:00 by goc30
 
flasherror
Senior Member

Joined: 07/01/2019
Location: United States
Posts: 159
Posted: 11:38am 07 Jun 2020
Copy link to clipboard 
Print this post

  panky said  @flasherror

Re your question 1, I can not see any way to achieve what you need here, sorry. Holding the settick counter from incrementing while in another set tick interrupt sort of defeats the purpose of a periodic tick.


The intent is not really to hold the the tick at its current count but the only way to temporarily pause the timer and have it not generate an interrupt is to do SETTICK 0,x,x which DOES disables the timer but when you restart it the internal count is reset. If I disable a 100mS tick when it has 50 mS to go then when I restart it I believe it will restart at 0 and thus take 100mS until it interrupts (instead of the remaining 50mS)

The real issue is that there is no "disable/enable global interrupts" or "disable/enable specific tick interrupt without disturbing its internal count" commands.


  panky said  @flasherror
Re question 2, as far as I know, there is no way of directly disabling all interrupts. My suggestion would be to have a flag, say GlobalIntDisable = 1, which you would include as the first statement in all interrupt service routines and then as the very last line in your ISR, GlobalIntDisable = 0.

In your mainline program, before changing any variable that is embedded in an interrupt service routine, you would check to see if you were inside an interrupt or not by testing the flag. Nested interrupts may get messy however without further flags.


I was thinking of this if there is no other solution. As you say it does have the potential for messy code but if that's the only way I'll have to do it.

Geoff, Peter, this might be something to improve in MMBasic. I will eat the biggest chocolate cake I can find if this is implemented for Duinomite.
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10577
Posted: 11:51am 07 Jun 2020
Copy link to clipboard 
Print this post

Like others I don't really understand what you are trying to achieve. In a uP if you disable global interrupts different things happen for different devices. For example edge triggered interrupts will be lost as likely will timer interrupts. Comm interrupts will probably happen when interrupts are re-enabled, USB will just go badly wrong.

If you want interrupts to be lost then just use a global variable and test for it at the top of each interrupt routine

Dim InterruptsEnabled=1
sub myint
if not InterruptsEnabled then exit sub
.........
end sub


If you want interrupts to be stacked then have the interrupt routine just set a flag or increment a flag and test for it in the main code as goc30 suggests

There is no single logic that could be implemented in the firmware which could be universally applicable
 
flasherror
Senior Member

Joined: 07/01/2019
Location: United States
Posts: 159
Posted: 11:59am 07 Jun 2020
Copy link to clipboard 
Print this post

  KeepIS said  
Tick interrupts are right at the bottom of the pile as far as interrupt request priority goes, and the priory is then from 1 to 4 for the tick interrupts.  

You could possibly use this to your advantage, as all other interrupts are disabled within the current interrupt. Using a higher tick interrupt to change the variables of the lower priority interrupt, but this still leaves the problem of accounting for interrupting at the correct time and allowing for internal MM Basic overheads that might throw you off.  


Your idea might work something like?
The minimum timer resolution for SETTICK is 1mS so main sets a high priority (SETTICT x,x,1) tick which in turn either:
1. sets a shared variable using a separate variable that only main writes
2. reads a shared variable into a separate variable that only main reads
(The separate "main only" var avoids contention and potential conflict between main and SETTICK interrupt code. But this might not work as well for UART receive since it has higher priority than TICK code?)
This is just a first thought, let me know if there is a better way.

  KeepIS said  
The problem with wanting to keep the tick period repeating (without stopping and starting) or even using a flag, is that its timing would still be variable and dependent on a number of higher priority interrupts and delays in code execution in those interrupts, assuming your using some like CFunctions, Touch, Key input, I2C, Serial Communications, GUI and IO interrupts as all have higher priority.


I understand the issue with potential delays but the delays are acceptable (main code either wants to check a flag that is set by tick or uart receive code OR wants to reset or indicate something to interrupt tick or uart code by setting a flag or variable). A little delay here would be OK.
 
flasherror
Senior Member

Joined: 07/01/2019
Location: United States
Posts: 159
Posted: 12:17pm 07 Jun 2020
Copy link to clipboard 
Print this post

  matherp said  Like others I don't really understand what you are trying to achieve. In a uP if you disable global interrupts different things happen for different devices. For example edge triggered interrupts will be lost as likely will timer interrupts. Comm interrupts will probably happen when interrupts are re-enabled, USB will just go badly wrong.

If you want interrupts to be lost then just use a global variable and test for it at the top of each interrupt routine


OK this is perhaps a clearer version of what I want to do:

1. I'm trying to read/write to shared variables between main and interrupt code (SETTICK, UART) without having to worry about an interrupt firing during main code and messing up something.

2. For tick interrupts I don't want the interrupt to necessarily be lost, just delayed. If I have a 100mS tick and it is about to fire and I disable it using your suggestion to test at top of ISR then it will be another 100mS before (another) tick occurs.

What I wanted to do is handle it like assembly:
1. Main needs to access a shared variable so disables global interrupts enable (meanwhile timer is about to be triggered)
2. Main does what it has to do and then renables interrupts
3. The pending interrupt now fires when interrupts enabled, since the timer interrupt flag was set even though global interrupts enable flag was disabled
In this case, the timer interrupt is delayed, not lost.

So, I want to safely access shared variables (in main code) while delaying pending interrupts.
Being able to temporarily disable (and reenable) certain interrupts (e.g. SETTICK) without affecting its internal count would be helpful (rather than disable global interrupts which would have other repercussions). This would simplify not having to set/test flags to see if it is "safe" for main to access shared variables.

  matherp said  
If you want interrupts to be stacked then have the interrupt routine just set a flag or increment a flag and test for it in the main code as goc30 suggests


Yes, this might be the easiest solution I've seen. Does this mean I still can't eat that chocolate cake?  
Edited 2020-06-07 22:37 by flasherror
 
CaptainBoing

Guru

Joined: 07/09/2016
Location: United Kingdom
Posts: 2171
Posted: 12:47pm 07 Jun 2020
Copy link to clipboard 
Print this post

hi FlashError.

depending how quickly your ticks are firing, you could look at this module I did a while back.

http://www.fruitoftheshed.com/MMBasic.AFTER-EVERY-REMAIN-Flexible-State-Machine-Timers-using-Semaphores.ashx

In that article I run the ticks every second but you can do them much faster if you like. It uses a single SetTick to run a master timer core that then triggers (in this example) 10 individual timers that only set relevant flags - you have to check the flag to see if you need to do something. This stops the firmware hi-jacking your code which can be an issue sometimes - as you have found out  

It has one-shot and repetitive timers and you can stop them individually (or just query the remaining time until it fires) - There is also a master disable/enable

just an idea that might help you get there
Edited 2020-06-07 22:55 by CaptainBoing
 
robert.rozee
Guru

Joined: 31/12/2012
Location: New Zealand
Posts: 2465
Posted: 02:40pm 07 Jun 2020
Copy link to clipboard 
Print this post

  flasherror said  My question is:
1. how would you temporarily halt the tick without affecting its internal count and restart it?
I guess one way of handling this is to use a semaphore (flag variable) to control whether the code in the T1_ISR executes by using a flag like:
T3_ISR:
if T3_enabled = 1 then
' do stuff
endif
ireturn


2. How to disable "tick" code from executing while you modify internal variables that may be shared between main code and the tick ISR code?
In assembly you'd do a "disable global interrupts" instruction to ensure that no interrupts can run while you are examining/modifying shared variables.
How would you do the same thing in MMBasic?


i suspect everyone may be excessively complicating the problem.

FIRSTLY, you want to have a periodic event happen, with it ok for the event to be occasionally skipped where necessary, but without interfering with what one might call the 'beat'. a bit like a clock that chimes every hour, but every now and then the chime fails to sound. yes? for this, the solution you propose is correct, and i can see nothing significantly better or more elegant.


SECONDLY, you worry about a timed interrupt being serviced part-way-through an mmbasic instruction in your main loop, yes?

with mmbasic, this simply does not happen. mmbasic code is atomic at the level of the statement, so something like A=B+sin(c) can not be interrupted. what we think of as basic interrupts are (with a few notable exceptions) only processed either between the lines of basic code in your main program, or between pieces of code separated with a colon (:). the result is that the call to a BASIC ISR may end up be delayed by up to 50ms or so - this is just in the nature of mmbasic.

with the timer interrupts:
the pic32 processor has a hardware counter that is incremented periodically, i'm guessing something like every 1us. when you set up a periodic interrupt using SETTICK period, target [, nbr] this hardware counter is (a) immediately read, (b) period is added to it, and (c) the result saved in a safe place. then, after each basic statement in your main program is processed, the mmbasic firmware (d) checks to see if the hardware counter is greater than the saved sum from (c), and if it is (d) the saved sum has period added onto it again, and (e) the routine target is called.

provided target completes in much less time that period, everything is hunky dory. basic statements take approximately 50us to complete according to Geoff (micromite, 40MHz clock), which equates to a BASIC ISR containing less than about a dozen statements or thereabouts to run in less than the minimum possible period of 1ms, and ideally only two or three statements.


the 'notable exceptions' to the atomicity of statements is (as i recall) INPUT, PAUSE, and possibly DS18B20/TEMPR. but while waiting at these statements no other basic code from your main program is being executed anyway.

so really, you generally don't need to worry too much. and if you do need to process a block of data or something similar without it being updated by a periodic timer event, just use a semaphore/flag.


if you can post an example (or rough outline) of the code you think may be problematic, i am pretty sure someone will be able to come up with a simple workaround to get around any issues with the main and periodic timers getting tangled up.


cheers,
rob   :-)
Edited 2020-06-08 00:50 by robert.rozee
 
JohnS
Guru

Joined: 18/11/2011
Location: United Kingdom
Posts: 4139
Posted: 03:53pm 07 Jun 2020
Copy link to clipboard 
Print this post

Rob,

I suspect you meant 50us in "may end up be delayed by up to 50ms or so"

John
 
robert.rozee
Guru

Joined: 31/12/2012
Location: New Zealand
Posts: 2465
Posted: 11:51pm 07 Jun 2020
Copy link to clipboard 
Print this post

oops, yes - it should have been 50us  
 
flasherror
Senior Member

Joined: 07/01/2019
Location: United States
Posts: 159
Posted: 02:55am 08 Jun 2020
Copy link to clipboard 
Print this post

  robert.rozee said  
SECONDLY, you worry about a timed interrupt being serviced part-way-through an mmbasic instruction in your main loop, yes?

with mmbasic, this simply does not happen. mmbasic code is atomic at the level of the statement, so something like A=B+sin(c) can not be interrupted. what we think of as basic interrupts are (with a few notable exceptions) only processed either between the lines of basic code in your main program, or between pieces of code separated with a colon (:). the result is that the call to a BASIC ISR may end up be delayed by up to 50us or so - this is just in the nature of mmbasic.

I understand what you are trying to say (MMBasic "interrupts" do not occur midway through basic statements) but my concern is if I have more one access to a shared variable, or if I need to read/modify multiple variables on multiple BASIC statements, then I need to avoid contention between main and interrupt modifying variables.

1. I am thinking about ignoring the tick via flag that is checked at start of tick interrupt code, and increasing the timer period (maybe 20mS instead of 100mS) to make up for a "lost/ignored" interrupt here and there.

2. But I am having trouble understanding the reverse version, where main attempts to check if any interrupt code is running:
Each ISR (SETTICK) sets its own "I'm running now" global flag which main can check before accessing shared variables. But if main code may be multiple statements doing shared variable access, how do you guarantee that Interrupt does not run say IMMEDIATELY AFTER you do the check, and while main is modifying shared variables?

#1 looks much simpler to me, but the occasional "lost" tick interrupt means that some I/O debounce might require shorter tick periods to make up for a lost one which could affect debounce results?

  robert.rozee said  
if you can post an example (or rough outline) of the code you think may be problematic, i am pretty sure someone will be able to come up with a simple workaround to get around any issues with the main and periodic timers getting tangled up.

I haven't written the code yet (because I was thinking about the shared main/interrupt variable access issue) but I'll post what I come up with in a few days to this thread.

By the way the MMBasic manual v4.5 mentions:
For most programs MMBasic will respond to an interrupt in under 100µS.
Interrupts can occur at any time but they are disabled during INPUT statements
For DS18B20 command: The time required for the overall measurement is 200mS and the running program will halt for this period while the measurement is being made. This also means that interrupts will be disabled for this period


Thanks for the detailed comments on MMBasic processing - would be nice if the MMBasic manuals had a "behind the scenes/for advanced users" section that gave some background details like this.
 
KeepIS

Guru

Joined: 13/10/2014
Location: Australia
Posts: 1955
Posted: 03:32am 08 Jun 2020
Copy link to clipboard 
Print this post

This may sound crude, but I was thinking, just as a matter of interest (fun):

Since other interrupts are disabled while a current interrupt is being serviced, Have you thought of leaving your 100ms as it is and simply using a second interrupt enabled to a tiny time period in the main code loop. That ISR, triggered almost instantly from the main loop will change the variables for / from the main loop. The 100ms ISR cannot trigger while the main variables are being changed in that ISR and that works both ways. As you know, you don't have to stop an ISR outside of the ISR so the main ISR can halt itself. The main loop code simply enables the change shared variables ISR, it runs almost instantaneously, there should not be a clash with two parts of the code trying to change the same shared variables and there should be minimal effect on the 100ms ISR timing.

No need to reply if this sounds a bit crude.
NANO Inverter: Full download - Only Hex Ver 8.1Ks
 
Chopperp

Guru

Joined: 03/01/2018
Location: Australia
Posts: 1106
Posted: 04:55am 08 Jun 2020
Copy link to clipboard 
Print this post

  flasherror said  
For DS18B20 command: The time required for the overall measurement is 200mS and the running program will halt for this period while the measurement is being made. This also means that interrupts will be disabled for this period
.


I you are worried about this one holding up procedures, don't forget you can use:-
DS18B20 START pin [,precision] first to start the procedure & then use DS18B20(pin) a bit later on in the program (depending on the precision used), to capture the reading.

Brian
Edited 2020-06-08 14:56 by Chopperp
ChopperP
 
panky

Guru

Joined: 02/10/2012
Location: Australia
Posts: 1116
Posted: 05:40am 08 Jun 2020
Copy link to clipboard 
Print this post

@flasherror,

Interesting post mate, lots of insightful comments.

IMHO, modifying a global variable in two (or more) distinct areas is fraught with danger from a programming perspective - it just has the tendency to make things ugly and hard to tie the logic down, particularly if the two modifying routines are unaware of each other, eg. a mainline section and an ISR.  Even more so if the ISR happens to be asynchronous (ie. you can't predict when it will occur).

Again, purely a suggestion but I think as referred to above by several other responders, set a flag in the ISR, if the data is critical, push it onto a stack then in your main routine, test "did an interrupt occur?", if so pull the data off the stack, either before of after the main code section as appropriate (ie. whichever is more important sequence wise).

Cheers,
panky
... almost all of the Maximites, the MicromMites, the MM Extremes, the ArmMites, the PicoMite and loving it!
 
KeepIS

Guru

Joined: 13/10/2014
Location: Australia
Posts: 1955
Posted: 09:32am 08 Jun 2020
Copy link to clipboard 
Print this post

BTW I had a chance to try a simple program changing global variables in an ISR with the main program loop starting a 1ms ISR to change the value. Each ISR printed the value set by the other, it obviously worked perfectly, there was never a clash nor could there be.

I used the sys timer to time from the point that main set the 2nd ISR to change the variable, print it and return to main, for a 1ms ISR it was 2.03ms. The 100ms ISR ran like clockwork, was never interrupted and always reflected the correct change, it's  value was always returned correctly to the main loop. Neither interfered with the other. It worked exactly as you would expect and as documented.
NANO Inverter: Full download - Only Hex Ver 8.1Ks
 
robert.rozee
Guru

Joined: 31/12/2012
Location: New Zealand
Posts: 2465
Posted: 11:08am 08 Jun 2020
Copy link to clipboard 
Print this post

  flasherror said  2. But I am having trouble understanding the reverse version, where main attempts to check if any interrupt code is running:
Each ISR (SETTICK) sets its own "I'm running now" global flag which main can check before accessing shared variables. But if main code may be multiple statements doing shared variable access, how do you guarantee that Interrupt does not run say IMMEDIATELY AFTER you do the check, and while main is modifying shared variables?


1.if an ISR sets a flag at the beginning, and clears it at the end, then neither the main program nor any other ISR will ever see that flag set. this is because mmbasic ISRs run from start to end without any interruption. and, as far as i am aware, ISRs can not interrupt each other... it is simply the case that after each line of basic code in your main program, there is a list of ISRs that may be called (if the associated trigger event has occurred) one after the other; once all have been called, the next line of basic code in your main program is processed.

2.  you are correct, that it is quite possible, unless blocked with a semiphore/flag as previously discussed, for an ISR to be called between any two lines in your main program. however, it would be a somewhat odd design of program where both ISR and main program can both access the same set of variables in a way that creates conflict. ISRs are just there to grab data and place it somewhere, set flags, and do other generally menial tasks. like minions.


generally, you arrange things so that an ISR writes to a variable, while the main program only ever reads from it. OR, that the main program writes to a variable, and the ISR only ever reads from it.

a common way of communicating between ISR and main program is via a circular buffer (sometimes called a ring buffer):

Dim buffer(255)

SetTick 50, isr50ms
Do
 If head<>tail Then
   Print "the ascii code is 0x" Hex$(buffer(tail), 2)
   tail=(tail+1) Mod 256
 EndIf
Loop


Sub isr50ms
 Local key$
 key$=Inkey$
 If key$<>"" Then
   buffer(head)=Asc(key$)
   head=(head+1) Mod 256
 EndIf
End Sub


in the above example: head is only even written to by the ISR, while tail is only ever written to by the main program. and because the statement in the main program If head<>tail Then is atomic, you are assured that the 4-byte float held in head can never have been partially updated by the ISR - an issue that often catches young players with C, assembler, etc.


cheers,
rob   :-)
Edited 2020-06-08 21:44 by robert.rozee
 
KeepIS

Guru

Joined: 13/10/2014
Location: Australia
Posts: 1955
Posted: 09:55pm 08 Jun 2020
Copy link to clipboard 
Print this post

A ring buffer is also how I do most of my streaming communication interfaces.

But I keep coming back to the simple task as outlined by the OP, and for the purpose of simply changing a few variables in a 100ms ISR while insuring that the main loop can also change those variables without either clashing, then for such a simple task, why not make use of the documented behaviour of the platform your programming on.

In this case you can absolutely grantee that the 100ms ISR will never change the variables while a 1ms Run-once Main loop variable update ISR is running, and neither will ever interrupt the other, and it's only 4 lines of code to implement in the main loop. The 100ms ISR does not a single line of code changed or even need a flag.

But if the OP is wanting to do more than just access / read modify a few variables then absolutely, go with a ring buffer or a shorter FIFO stack, depending on timing and exactly what the OP is trying to accomplish.

As far as disabling global interrupts, I can remember only using that when loading far pointers in assembler back it the 8080 days and a variation of that a few years back with some Microchip devices, again in assembler.

It would have been nice to have had that global option in MM Basic (even for a few ms) to wrap a few lines of time sensitive code in. The only work around is to set a Flag in every ISR, especially the two Touch screen ISR, and abort the result of the  time critical IO code, all because the user pressed the Touch Screen or turned an encoder. Obviously we will never have that option, it's a rare case that you would actually need it anyway, and there is always a work around.
.
.
Edited 2020-06-09 08:33 by KeepIS
NANO Inverter: Full download - Only Hex Ver 8.1Ks
 
flasherror
Senior Member

Joined: 07/01/2019
Location: United States
Posts: 159
Posted: 01:38pm 09 Jun 2020
Copy link to clipboard 
Print this post

  KeepIS said  A ring buffer is also how I do most of my streaming communication interfaces.

But I keep coming back to the simple task as outlined by the OP, and for the purpose of simply changing a few variables in a 100ms ISR while insuring that the main loop can also change those variables without either clashing, then for such a simple task, why not make use of the documented behaviour of the platform your programming on.

In this case you can absolutely grantee that the 100ms ISR will never change the variables while a 1ms Run-once Main loop variable update ISR is running, and neither will ever interrupt the other, and it's only 4 lines of code to implement in the main loop. The 100ms ISR does not a single line of code changed or even need a flag.

You're probably right with regards to the roundabout way of solving the problem, but I think there SHOULD be a way to temporarily prevent a SETTICK interrupt without disabling it via SETTICK 0,x,x since there is NO WAY to re-enable it with its previous internal count

The tip you've suggested might be able to work but has a few disadvantages:
1. it takes up a SETTICK interrupt (there are only 4 available) and for best results it should use SETTICK x,x,1 (the first int is the highest priority) so in the event of multiple interrupts occurring at the same time our 1mS one will execute first.
2. it still requires a 1mS delay for main to effect whatever change it wants to make.

I have been thinking that a modification to SETTICK command would be useful in doing the straightforward solution to this problem, namely being able to temporarily disable the SETTICK interrupt without disabling it (and NOT resetting its internal count when it is re-enabled).

SETTICK normally takes a positive number 1 to 2147483647 (0 is used to disable it)
What about the ability to do:
SETTICK -2,x,x which will temporarily disable the interrupt code from running but maintain its current internal count.
SETTICK -1,x,x to re-enable the interrupt, continuing with the previous internal count for the timer (and executing the interrupt code if the time for it to fire has elapsed, even if it was disabled)

I do not know if the current internal details of MMBasic would lend itself easily to this change.

  KeepIS said  
But if the OP is wanting to do more than just access / read modify a few variables then absolutely, go with a ring buffer or a shorter FIFO stack, depending on timing and exactly what the OP is trying to accomplish.

It would have been nice to have had that global option in MM Basic (even for a few ms) to wrap a few lines of time sensitive code in.
.

The ring buffer suggestion is a solution to something other than what I'm trying to solve. Note in previous posts when I refer to being able to disable "global interrupts" I mean from the perspective of MMBasic code that is running, not necessarily chip global interrupts - obviously that would mess with MMBasic's internal workings!
I agree 100% with the time sensitive code - even though Basic is interpreted there are some situations where it would be nice to have a bit more control.
Edited 2020-06-09 23:45 by flasherror
 
     Page 1 of 2    
Print this page
The Back Shed's forum code is written, and hosted, in Australia.
© JAQ Software 2025