The wikipedia entry states:
In computer system programming, an interrupt handler, also known as an interrupt service routine or ISR, is a callback function in microcontroller firmware, an operating system or a device driver, whose execution is triggered by the reception of an interrupt.
How is ISR a callback. Is it the PC value stored on stack itself is the callback function?
I.e., the ISR calls the interrupted function back. Hence the interrupted function is a callback.
A bit of setup code stores the address of the ISR function in the interrupt vector table to say "call me back at this address when the interrupt occurs".
To be clear, the ISR itself is the function that is "called back". The interrupted code is not the callback; it is merely "interrupted" and later "resumed".
ISR calls the interrupted function back
No, it doesn't, the program counter register is restored from stack like the return instruction does. ISR is a 'callback' because it is called via its address (stored in an interrupt vector table), and not directly.
Micro-controllers have an interrupt vector table in their flash memory at a known location. The table contains the addresses of all the ISR (reset interrupt, timer interrupts, GPIO interrupts, etc.). When an interrupt is enabled, on a specific trigger the ISR function is called: the application program is interrupted, the program counter and the processor registers are saved in the stack and the interrupt code is called. When the interrupt code is finished, the application is restored and the application program is resumed.
Related
We have a product that uses an MSP430F5436A. It has been in production for several years. Over the past several months we have had reports from production that a few units are not shutting down completely, their power LED is staying on. The power LED is driven by an I2C GPIO expander, it's not connected directly to the MSP430.
When the user hits the power button the MSP430 is supposed to shut down a lot of peripherals, turn off the power LED, and enter LPM2. Periodically a timer interrupt wakes it up from LPM2 to check to see if the power button has been hit to turn the device back on and to do some other house keeping.
After the user hits the power button there is a delay before the device powers off which is driven via a timer ISR. I ripped that out and put in a delay loop. Within that delay loop I am rapidly toggling a different LED that is connected directly to the MSP430.
If I make the loop duration shorter than two seconds the device is able to get into LPM successfully and the LED stops toggling. If I set the loop longer than two seconds I can observe the lock up behavior I am seeing. Sometimes the LED is left in an on or off state, that is random.
I have attempted to disable all maskable interrupts prior to entering the loop. That had no effect. I also put code in the SYSNMI and UNMI vectors to detect if either of those were firing and neither is firing. Also, there is no RTOS, this is a cooperative multi-tasking system. So it seems to be locking up while executing the loop its self.
Eventually my device reboots from this lockup but it is due to a watchdog reset. I print the reset source at startup. The device also recovers if I pull out and reinsert the battery. However, the device stays in a locked up state if I pull the reset line low. I also have trouble JTAGGing firmware onto the device once it is locked up.
I've looked in the errata for the MSP430F5436A for mentions of lock up behavior and the only mention isn't relevant.
Unfortunately, due to the packing and construction of the device it is difficult to probe some of the nets, but not impossible.
I can connect to the device with a debugger, but the debugger (CCS 7 + MSP-FET430UIF) looses its connection with the device shortly after the device starts running. That is something that is always true and is a design issue. We have frequent timer interrupts occurring so this behavior may not be avoidable.
The power source for the device is stable and it is operating on my bench and not in a high EMI/EMF environment. However, when this loop occurs some peripherals and power supplies would have been shut down. So it is possible some sort of anomaly is occurring on one of the MSP430's power rails or a GPIO pin.
What could be causing this lock up behavior? Are there any persistent registers I can read on reset that would give me a clue, or are there any pins/nets I can probe that would give me a clue?
Update:
I have probed VCC for the MSP430, rails that power peripherals the MSP430 is connected to, and the reset line. I see no changes on any of these at the time of the lock-up.
Edit:
The following is the delay loop that I added
dprintf(PRINT_LOG, "Entering delay loop");
__disable_interrupt();
enable_backlight();
for(uint16_t j = 4u; 0u < j; --j)
{
__delay_cycles(14680064/20); // ~50mS delay w/ 14.680064 MHz MCLK
toggle_backlight();
}
disable_backlight();
__enable_interrupt();
dprintf(PRINT_LOG, "Exiting delay loop");
I incorrectly assumed that the hang was occurring within my delay loop because interrupts were disabled, and that the loop wasn't completing. It turns out the loop is running to completion, and after interrupts are enabled an ISR is entered for an event that occurred during the execution of the loop. The hang occurs in that ISR.
Shortly after the delay loop (in time, but somewhere else altogether in code) a GPIO interrupt is disabled. When I power down the device a peripheral that is holding a pin high is shut off, and that pin eventually drops. If I make the delay loop short the loop is exited and that particular interrupt is disabled before the pin drops. If the delay loop is long the pin drops and when the GIE bit is reset by __enable_interrupt(); a context switch to that GPIO interrupt begins.
I'm working on some application using Qt framework, it uses serial port and need to receive some data, problem is that data is organized with some protocol, which i parse in readyRead() signal handler(slot), at the same time, i need to wait for parsed message with some timeout. So, to wait, i use QThread::msleep() after sending, but i've noticed, that when thread goes to sleep in msleep(), readyRead will be emitted only after msleep() will be finished. My question is, why readyRead can't wake up thread? Qt signal is not working like real Unix signals?
If you have single thread application readyRead slot not executes immediatly you got data on port. Read about Qt::QueuedConnection in QObject::connect(). When readyRead signal emits in serial port class it just added to queue of events (in global event loop). All events will be executed later by QEventLoop (inside QApplication instance).
Looks like you sleep your main thread so QEventLoop cant execute anything while sleeping. In this case you need to read your port from another thread to avoid main thread sleeping.
Currently working on msp430fr5969. I have multiple interrupt like SPI, I2C, Timer and the requirement is the SPI protocol is the highest priority.
However, according the datasheet, the priority of I2C(eUSCI_B0) higher than SPI(eUSCI_A1) and cant change the interrupt priority.
Link: http://mikrokontroler.pl/wp-content/uploads/pliki/msp430fr5969.pdf (page 21).
How I can get into SPI interrupt as fast as possible while I2C process?
I got stuck while I2C's reading and It has a data sent from another MCU. the MCU notify a timeout in that case. Its rarely but I want to fix it.
Note: use SPI to communicate with another MCU so its importance data.
Use I2C for readding information from sensor.
The interrupt priorities matter only if two interrupt flags are set before the CPU is able to handle one of them, and the CPU has to decide which one to handle first. In practice, this almost never happens.
When an interrupt handler executes, all other interrupts are blocked (GIE is cleared by default), regardless of priority. This means that when the I²C interrupt handler is currently executing and the SPI interrupt happens, the SPI handler begins execution only after the I²C handler has finished.
To execute the SPI handler with a high priority, you have to ensure that all other interrupts do not block it, at least not for a long time. This is typically done by those interrupt handlers just setting a flag that indicates that the device needs attention, and then handling these conditions in the main loop of your application.
You could technically reenable gie withing other interrupts to enable interrupt nesting.
This way you can manage interrupts execution order by adding some logic as preamble to interrupts. Personally I'd rather avoid it and keep it as last resort. Try to keep other interrupts code short, manage logic outside interrupts, and if it is not enough try to disable other interrupts while you expect the critical interrupt to come (if it is possible).
I am counting pulses using an external interrupt, but I put the processor to sleep in between pulses using wdt_enable, using the 8-second interval.
When the interrupt occurs and the processor wakes up to service the interrupt, is it possible to find out how long into the 8-second period I am? That is, can I read the wdt timer to see how long it has been running (or how long it has to go)?
The ATMEL328p Datasheet Page 51 shows the architecture of the Watchdog. There does not seem to be a method to read back the Watchdog Prescaler. The answer assumes you are using an Arduino with a 328p.
In the Intel 8085 microprocessor, precisely at what point (t state) does the program counter get updated? Is it just after t1 (i.e., just when the current address in the PC is placed on the address bus) or at t3, when the instruction fetch is being done?
Also, when a hlt instruction is encountered, what happens to the state of the program counter? Does it get incremented or does it contain the address of the current hlt instruction?
Similar question has been asked at this.
Usually in the first clock cycle the current value of the PC is loaded into the address buffer, and next 2 clock cycles fetches the instruction opcode at that address.
During this time the 16-bit PC is updated by the incrementer while the opcode is being fetched into the IR. So PC is already incremented before the 8085 can even decode and realize that the instruction is HLT.
HLT works as a "wait for next interrupt" instruction. If you want to halt forever, you have to put HLT in a loop, or disable interrupts. So the saved interrupt-return address that's software visible inside the interrupt is the byte after HLT.
This is what happens on 8086 / x86, and 8080 is asm source compatible. Also, having the interrupt return address point at HLT would mean it would run again after an interrupt handler returned normally. Using it as anything other than a "only run interrupt handlers from now on" would mean that all your interrupt handlers would have to check what the saved PC was pointing to, and if so increment it before return. Instead, to get that behaviour you put HLT in a loop at the one place you want that.
As codeR explains, PC has already been incremented before HLT sleeps, not at the last moment when waking up to handle an interrupt.