![]() |
Forum Index : Microcontroller and PC projects : Line/statement execution and Interrupts
Page 1 of 2 ![]() ![]() |
|||||
Author | Message | ||||
MustardMan![]() Senior Member ![]() Joined: 30/08/2019 Location: AustraliaPosts: 175 |
Hi, I've looked through the manuals, and searched on the forum, but have not been able to find a definitive answer as to how basic responds to interrupts. The documentation (and forum) stipulates that interrupts are generally responded to "within 50uS" or "within 100uS" depending on where you read. Some commands/functions delay this, for example some one-wire commands, writing to flash. How does basic handle interrupts when processing a line? For example (really simple stupid example, but to illustrate a point): a$ = a$ + b$ + c$ : a$ = a$ + d$ + e$ a$ = a$ + f$ + g$ An interrupt event happens between concatenating b$ and c$, and the ISR code does: a$ = a$ + i$ Are interrupts held off while executing a statement, or executing a line, or not disabled at all unless specifically disabled (eg: as they are during the DS18B20 'TEMPR(n)' function)? So, for the above code, what would I get? 1] ABiCDEFG 2] ABCiDEFG 3] ABCDEiFG Also, how (or can) interrupts be disabled by basic? The "Getting Started With the Micromite" Version 6 manual says, on page 54, 3rd dot point, talking about nested interrupts : "If you must call a subroutine...must disable the interrupt first...then reinstate it after..." I know my example is not a nested interrupt, but could I do: disable interrupts : a$ = ..... ..... : enable interrupts and what is the command to do this, I can't find one... is there one? Cheers, |
||||
TassyJim![]() Guru ![]() Joined: 07/08/2011 Location: AustraliaPosts: 6283 |
You have to disable each individual interrupt. There is no global disable/enable So for SETTICK: These interrupts can be disabled by setting ‘period’ to zero (ie, SETTICK 0, 0, 3 will disable tick timer number 3). When running, interrupts are checked at the end of each line so a one-liner will not get interrupted but can cause interrupts to be delayed. Jim VK7JH MMedit |
||||
thwill![]() Guru ![]() Joined: 16/09/2019 Location: United KingdomPosts: 4311 |
End of each line ? or end of each statement ? Tom Edited 2020-11-14 06:56 by thwill MMBasic for Linux, Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
Geoffg![]() Guru ![]() Joined: 06/06/2011 Location: AustraliaPosts: 3292 |
Interrupts are checked at the end of each statement. So, in MustardMan's example he will get ABCiDEFG. Jim is right in that there is no global interrupt disable so you need to disable each interrupt individually (not hard to do). Geoff Geoff Graham - http://geoffg.net |
||||
TassyJim![]() Guru ![]() Joined: 07/08/2011 Location: AustraliaPosts: 6283 |
You are right, it get checked after each statement SETTICK 1000, ticktock, 1 PRINT "start "; TIME$ PAUSE 10000 PRINT "first pause ended"; TIME$ SETTICK 0,,1 ' interrupt disabled PAUSE 10000 PRINT "second pause ended"; TIME$ SETTICK 1000, ticktock, 1 ' interrupt re-enabled DO:LOOP SUB ticktock PRINT "tick "; TIME$ END SUB Jim VK7JH MMedit |
||||
MustardMan![]() Senior Member ![]() Joined: 30/08/2019 Location: AustraliaPosts: 175 |
Thank you all for the quick and informative replies. My question stems from my assembler background where interrupts can slip in between any instruction, but can't interrupt the instruction itself - although I don't know how it works for "long" instructions like a hardware multiply or divide. I also don't know what happens when a more complex CPU executes a SIMD instruction. The older I get, the more I realise I don't know! Obviously all higher level languages have to execute multiple machine instructions to execute a 'statement atom' (eg: a = b + c), so knowing the 'statement atoms' can't be jumped into by an interrupt is very useful info. Thanks everyone! |
||||
JohnS Guru ![]() Joined: 18/11/2011 Location: United KingdomPosts: 4044 |
Some CPUs do interrupt mid-instruction e.g. Intel 86 family (read up on LOCK to overcome). MMBasic is nice in this regard! John |
||||
MustardMan![]() Senior Member ![]() Joined: 30/08/2019 Location: AustraliaPosts: 175 |
Ouch! SIMD? I never got into the 8086. I didn't like it one bit (no pun on that one). I started with Z80, later got into 8051. Both very nice architectures and instruction sets. Later looked at 6502, and compared to what I was used to thought it was rubbish. Then looked seriously at the 8086, but after intel made it so complex it wasn't funny, I'm really glad I steered clear. Then I started work at a place that used PIC. Expletive!! Let's just say I was not impressed with either the architecture or the instruction set (this was a couple of decades ago before microchip got a clue). Unfortunately all their new stuff has to be compatible with their old stuff, so most of it is still a POS. Thank god someone put an intense amount of effort (and it must have been intense) into developing a compiler for the PICs. Yes, they have great on-chip peripherals, but the rest! |
||||
Cyber![]() Senior Member ![]() Joined: 13/01/2019 Location: UkrainePosts: 161 |
Thank you for information! I want to add more questions for better understanding interrupts. Quotes from Micromite manual. What are the risks if I make an interrup that works long? My other interrupts will stay in queue and will all be delayed? Or am I risking that other interrupts will be lost? Is there a limit of this queue? And what happens to main program when long interrupt is working? Will the main program just wait for interrupt to end? Or main program and interrupt run in parallel? What if I don't? What will happen? |
||||
Geoffg![]() Guru ![]() Joined: 06/06/2011 Location: AustraliaPosts: 3292 |
So many questions ![]() You might miss other interrupts or your main program could get very little time to run. A common fault for new programmers is to spend too much time in interrupts and then wonder why their main program has stopped working or is running very slow. Generally you don't need to worry about an interrupt that occurs once a minute but if you have an interrupt that occurs every millisecond you need to look at it very carefully. Or am I risking that other interrupts will be lost? It depends. Most interrupts such as timer ticks (SETTICK), serial input, I2C, IR, etc will be held waiting for the current interrupt to finish. The big exception is interrupt on an I/O pin. For example, if your interrupt is set to occur when an input pin goes high (say a button press) then it is possible that the voltage will go high then low again while you were wasting time in an interrupt sub and the button press would not be seen and would be lost. There is no interrupt queue. At the end of each BASIC command the interpreter will check all possible interrupt sources in order of priority (page 40 Micromite manual). When MMBasic returns from the interrupt subroutine that particular interrupt will be cleared. The the main program will just wait for the current interrupt subroutine to exit. What if I don't? What will happen? If you have called the interrupt sub normally and an interrupt occurs while executing the sub MMBasic will call the sub a second time and any FOR loops, DO loops and static variables in the sub will be corrupted and possibly cause your hair to turn prematurely grey. Geoff Edited 2020-11-14 17:01 by Geoffg Geoff Graham - http://geoffg.net |
||||
Cyber![]() Senior Member ![]() Joined: 13/01/2019 Location: UkrainePosts: 161 |
Thank you very much for detailed answer, Geoff! Many things became clear for me. What if another interrupt happens, while one is already being held waiting? Will they both be waiting? Or is there only one waiting slot? |
||||
JohnS Guru ![]() Joined: 18/11/2011 Location: United KingdomPosts: 4044 |
Please - plan not to need the answers! Write VERY short interrupt routines if you cannot do without them entirely (e.g. Grogster posted the kinds of code that helps not need a COM ISR). Regard every non-trivial ISR as a disaster waiting to happen & nightmare to debug. The above applies in assembler, too. John Edited 2020-11-14 20:41 by JohnS |
||||
MustardMan![]() Senior Member ![]() Joined: 30/08/2019 Location: AustraliaPosts: 175 |
From my understanding of the PIC32 there are several interrupt slots, but many of them are shared. Without looking at the datasheet I could not say which are the shared ones. However, for the sake of argument say all the serial port peripherals share one interrupt (ie: SPI/I2C/UART). A perfectly valid thing to do, and the way you determine what caused the interrupt is by checking a subset of peripheral flag bits to find out which one (or ones) are causing all the trouble. The smaller micros often only have a single interrupt and it is therefore necessary to check all the flags (only for the interrupts you are using of course - not the whole lot!) But that is assembler stuff, and not C or BASIC, so I might be blowing smoke out my... Interrupts will "queue" up, if they are not shared. For example, a timer interrupt won't be shared with a UART interrupt. Take the scenario: the UART interrupt goes off, so you respond (execute your UART ISR), but you spend ages and ages in there. The timer interrupt goes off and will be queued to jump into its' ISR the moment you pop out of the UART ISR. The problem occurs if you get more than one timer tick while you are fooling about in your UART ISR, because the timer interrupt flag only gets set once. Similar things happen with other interrupts too (and has got me several times). |
||||
JohnS Guru ![]() Joined: 18/11/2011 Location: United KingdomPosts: 4044 |
If you hit any of those kinds of problems your ISR is WAAAAYYYY TOOOO LOOONNNGGG. Do the very bare minimum. John |
||||
Tinine Guru ![]() Joined: 30/03/2016 Location: United KingdomPosts: 1646 |
Regard every non-trivial ISR as a disaster waiting to happen & nightmare to debug. John ![]() Ever since I read Charles Petzold's Programming Windows, I have regarded interrupts as a last resort. |
||||
Cyber![]() Senior Member ![]() Joined: 13/01/2019 Location: UkrainePosts: 161 |
Everybody, thank you very much for all your useful answers!! They clear up things a lot. I understand it is a good practice, which simplifies code debugging. But I always thought of interrupts as an advanced and reliable feature, though hard to debug one. In fact many low level system things in PC are built on interrupts. Edited 2020-11-17 14:58 by Cyber |
||||
TassyJim![]() Guru ![]() Joined: 07/08/2011 Location: AustraliaPosts: 6283 |
Interrupts to do things that can not wait and set a flag. The main program loop can then process the events in an orderly manner. This usually helps stop unexpected things happening when a value gets changed mid-process. We don't have multiple threads in MMBasic although some things can happen in the background which can be similar. Jim VK7JH MMedit |
||||
Cyber![]() Senior Member ![]() Joined: 13/01/2019 Location: UkrainePosts: 161 |
The main program loop can then process the events in an orderly manner. This usually helps stop unexpected things happening when a value gets changed mid-process. Sounds like a golden mean. ) |
||||
MustardMan![]() Senior Member ![]() Joined: 30/08/2019 Location: AustraliaPosts: 175 |
Spot on... although a comma might make it clearer... Interrupts to do things that can not wait, and [often simply] set a flag. There are a lot of really good reasons to use interrupts, but you have to think about why you are using interrupts to do it, and if so, think about what/how your main program will respond. It is up to the human behind the code to work through the details... It is a very easy trap. I fell into it only last week with my code for reading a serial port... thankfully Grogster set me straight and made me realise I didn't need an interrupt at all! Changing variables unexpectedly is a common trap. For example: n is a scratchpad number. You use it as a temporary counter in your main code (eg:n=n+1 every time someone touches the touch screen), but the ISR also uses it for looping (eg: FOR n=1 TO 5). Main code is counting presses... interrupt happens... and now your main count is wrong. But most problems happen when the ISR takes longer than it should, especially when the ISR takes longer than the time between interrupts! Cheers, |
||||
Cyber![]() Senior Member ![]() Joined: 13/01/2019 Location: UkrainePosts: 161 |
Currently I'm thinking that interrupt is very handy for catching input pin pulse. Because if I check for it in a main program loop, I have a risk to miss it (if pulse is very short, and my main program loop is long). In this case interrupt with flag is a better choice. On the other hand I'm thinking that using interrupt for catching COM port input might not always be a necessary case. COM port has a buffer, where characters can wait for a while. And in most cases it does not hurt to check this buffer in main program loop. |
||||
Page 1 of 2 ![]() ![]() |
![]() |
![]() |
The Back Shed's forum code is written, and hosted, in Australia. | © JAQ Software 2025 |