Interrupts reflect the performance of a microcontroller to a large extent. From this point of view, MSP430 has done a good job in interrupts, mainly providing a very rich interrupt source, including IO interrupts, timer interrupts and some interface interrupts (SPI, UART, I2C) and so on. Now I will talk about some characteristics of MSP430 interrupts, mainly the issues that I feel are more useful in project experience, and share them with you. First, the priority of MSP430 interrupts. MSP430 supports interrupt priority, but how to know the priority level? There is a very interesting statement in its manual. I quoted it in the original text, "The nearer a module is to the CPU/NMIRS, the higher the priority", which means that the closer to the CPU/NMIRS, the higher the priority. So how do we know which module is close to the CPU? Look at the block diagram given in the datasheet? I always feel that this is impossible to reassure an electronic person, for example, if the block diagram is in the same distance from the CPU, how to distinguish it? So we have another more reliable way. IAR provides corresponding header issues for each model of 430, and you can know it just by looking at the interrupt vector address. The interrupt vector table of MSP430 starts from address 0xFFC0 and ends at 0XFFFF. There are 32 entries in total (each interrupt vector corresponds to 2 bytes). The interrupt vector corresponding to 0XFFCO has the highest priority, and the interrupt vector corresponding to 0XFFFE has the highest priority, that is, from 0xFFCO to 0xFFFF, the 32 interrupt priorities are from low to high. In this way, it is easy to figure out the priority of each interrupt. Second, the response process of MSP430 interrupt. First of all, of course, the flag corresponding to the interrupt is set to 1. I will explain the process in detail at this time. It is actually a translated user manual, but it is still good to understand it. 1. The CPU will execute the current instruction. 2. The PC pointing to the next instruction is pushed onto the stack. 3. The status register SR is pushed onto the stack. 4. Select the interrupt with the best priority for service. 5. The interrupt flag of a single-source interrupt will be automatically cleared. Be careful here because the interrupt flags of P1 and P2 will not be automatically cleared, because the IO interrupts of P1 and P2 belong to multi-source interrupts, that is, the 8 IOs of P1 or P2 correspond to an interrupt vector. The MCU knows that an interrupt has occurred in P1 or P2. No matter which IO of P1 occurs, it will point to the interrupt vector of P1. The same is true for P2, so it needs to be manually cleared in the code. 6. The status register SR is cleared, which will terminate any low-power state, and the global interrupt enable is turned off (GIE). This place is quite different from 51. After responding to the interrupt, 430 will turn off the global interrupt enable and will not respond to any other interrupts including those with high priority. That is to say, there is no interrupt nesting in the default state. If interrupt nesting is used, you need to use _EINT() to turn on the global interrupt. 7. The interrupt vector is loaded into PC and the interrupt service function begins to execute. The above is the entire interrupt reception process. I have marked the more important parts with color fonts. Interrupt return is relatively simple. The interrupt service function will return by the RETI instruction, SR will be popped up, the microcontroller will be restored to the state before the interrupt, and PC will be popped up to continue executing instructions. Third, open the interrupt and interrupt service function. This is the part that made me entangled in the project, and please be careful. Once the MSP430 opens the peripheral interrupt, such as the SPI receive interrupt. When the SPI receive interrupt is enabled, the microcontroller will load the interrupt vector once it finds that the SPI receive flag is set. But what if we don't use the SPI receive interrupt? Since it is not used, there is no SPI receive interrupt service function. At this time, what is the value of the interrupt service function address in the interrupt vector? It is all 0. The CPU fetches instructions from 0-01FFh, and only one thing will happen. PUC, power-on clear. Then PC will load the content of the 0xFFFE interrupt vector, that is, the reset vector, and the program will jump to the startup code we made for IAR. The program will execute to the first sentence of the main() of the code we wrote. This is how the tragedy was born, the machine is swung! ! ! ! So I hope that friends who are new to 430 will not enable interrupts if they are not used. If you enable them, you must write an interrupt service function, even if it is an empty function! 1. Interrupt nesting and priority The control bit of the 430 general interrupt is the GIE bit in the status register (this bit is in the SR register). When this bit is in the reset state, all maskable interrupts will not be responded to. Maskable interrupts are divided into single interrupt source and multiple interrupt sources. For a single interrupt source, the interrupt flag bit is automatically cleared after responding to the interrupt service program, while for multiple interrupt sources, the interrupt flag bit is required to be cleared after querying a certain register. Since the first microcontroller that most people come into contact with is usually 51, if a higher priority interrupt occurs during the response of the 51 microcontroller CPU to the low-priority interrupt program, the microcontroller will execute the high priority, and this process has generated interrupt nesting. The 430 microcontroller is different. If a higher priority interrupt service request comes when responding to a low-priority interrupt service program, the 430 will ignore it until the low-priority interrupt service program is executed, and then it will respond to the high-priority interrupt. This is because when 430 responds to the interrupt program, the general interrupt GIE is in the reset state. If you want to generate interrupt nesting similar to 51, you can only set the GIE bit again in the interrupt function. 2. Timer TA TimerA has 2 interrupt vectors. TIMERA0, TIMERA1 TIMERA0 only counts the overflow of CCR0. After querying TAIV, you can know whether it is caused by CCR1, CCR2, or TAIFG. As for the situation in which TAIFG is set, it depends on the working mode of TA. Please refer to the user manual. Another point is that TA itself has PWM output function, and there is no need to borrow the interrupt function. On this issue, the application detour often occurs in how to combine TA and AD to implement timed sampling. Many people open AD in the TA interrupt to do this. This is not appropriate, because the ADC10 and ADC12 (SD16 is not familiar, so I have no say) modules of 430 have pulse sampling mode and extended sampling mode. Just select AD to be sampled by TA trigger, and then set TA to PWM output mode. Of course, the special function pins are used to output PWM waves, but here it is not needed, so the pin settings do not need to be taken care of. What is worth paying attention to is the frequency of PWM, that is, the sampling rate of your AD. 3. Watchdog reset The watchdog has two working modes: timer. In the watchdog timer working mode, WDTIFG has a flag bit that automatically resets in response to the interrupt service program, while in the watchdog mode, the flag bit can only be cleared by software. But how to judge whether the reset is caused by the timing overflow of WDT working in watchdog mode, or by the error of the watchdog writing key? ……………………………… The answer is that there is no way, at least I have not seen any way, nor have I seen any way around me. If anyone knows the method, thank you for sharing. 4. People often ask the function of this statement MOV.B #LPM0,0(SP). If you are in standby mode in LPM0 before entering the interrupt function, and you want to enter standby mode in LPM3 after executing the interrupt function, writing MOV.B #LPM3,SR in the interrupt function is invalid. Because when entering the interrupt, 430 will push PC and SR to the stack (SR stores the low power mode settings). Even if you write MOV.B #LPM3,SR, SR will be reset to low power 0 when exiting the interrupt stack. To achieve this goal, you can only change the SR settings in the stack: MOV.B #LPM0,0 (SP). 5 Interrupt vector: The interrupt vector of 430 is FFE0H-FFFFH,There are 32 bytes in total, which is the last section of FLASH. The 430 FLASH may be large or small, but the final address is definitely FFFFH (except for large FLASH exceeding 64K), so their starting addresses are different. Generally, IAR defaults to compiling and puts the program at the beginning of FLASH (excluding the information section). A question worth clarifying is: What is an interrupt vector? The interrupt vector is actually the storage unit space that stores the entry address of the interrupt function. Just like the two bytes FFFEH+FFFFH are the reset interrupt vector, then it stores the starting address of the main function in FLASH. If the main function is stored in the FLASH block with 0x1100 as the starting address, then you will find that 0x11 is stored in FFFFH and 0x00 is stored in FFFE. Other TimerA, ADC12, all are the same. It's just that the length of the program you write each time is different, and the location of the interrupt function is different. The IAR compiler will set it for you, and then when you use JTAG to burn the program, burn this address to the corresponding interrupt vector. Because the address of the interrupt function can be customized by the user or automatically compiled by IAR, this address is unknown to others except the source code developer. BSL is a password set based on the particularity of the content in the 32-byte interrupt vector. However, there are a few things that remain unchanged in 430, that is, after the conditions for triggering the interrupt are met, where it goes to address the entry address of the interrupt service function is fixed and fixed when TI made 430. For example, when powering on and resetting, it knows to look for the address in the FFFE, FFFF units instead of FFE0, FFE2. This mapping relationship is fixed and unchanged in 430. But sometimes you just need to change the "interrupt vector", what should you do? Sometimes you will encounter this problem in the 430FLASH program self-upgrade. The solution is to do a jump operation in the original default interrupt vector table of 430. Take the power-on reset as an example: ORG 0x2345 PowerReset: mov.w &0xFCFE, PC ………………………… ………………………… ORG 0xFFFE DW PowerReset In this way, 0xFCFE is equivalent to the mapping of 0xFFFE. This is in the TI application report of the 430 program self-upgrade.