This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

MSP-EXP430G2: How to jump to another ISR when the code is executing an ISR?

Part Number: MSP-EXP430G2

Hello, I have a question when coding ISRs.

#include <stdint.h>
#include <msp430.h>

// button interrupt
#pragma vector = PORT1_VECTOR;
__interrupt void Port1_ISR(void){
    sw_debouncing();
    do_something_when_debounced();
    button_ifg_clear();
}

// ADC10 interrupt service routine
#pragma vector=ADC10_VECTOR
__interrupt void ADC10_ISR(void)
{
    uint8_t buffer[2];
    uint16_t data = ADC10MEM;

    buffer[0] = (uint8_t) ((data & 0xFF00) >> 8);
    buffer[1] = (uint8_t) (data & 0x00FF);

    uart_tx(buffer, 2);
    
}

I am sampling a signal with a sampling frequency 5000 Hz. When I sample the ADC data, I want to send it as 2 bytes using the UART (baud rate 115200, no parity, no flow control).

The UART sending part is working. However, I noticed that my button interrupt is not triggering.

I tested this by disabling the UART and the ADC to check whether this triggers or not.

If I disable both, the Port1 ISR triggers correctly.

I think the Port1 ISR doesn't get triggered because the UART sending (uart_tx) takes long inside the ADC ISR and when the code is inside the ADC ISR, it disables the global interrupt, doesn't it?

So my question is,

- Is there an option to enable the interrupt when the code is running the ISR?

- In this case, should I seperate the UART sending part from the ADC ISR and put it inside the main loop?

I let the MSP430 to go to sleep (Low Power Mode 0). So I'm also looking for an option to wake-up the MSP430 when the code is running inside the ISR.

  • All interrupts will remain pending so that after one ISR completes, any pending interrupts will be serviced. In priority order if there is more than one. So that isn't your problem. I don't see the code to initialize the ports and interrupts so I can't tell if the problem is there.

  • Hello David,

    Thanks for your detailed post.

    David__ said:
    I think the Port1 ISR doesn't get triggered because the UART sending (uart_tx) takes long inside the ADC ISR and when the code is inside the ADC ISR, it disables the global interrupt, doesn't it?

    As you can see in Table 5 in the MSP430G2x53, MSP430G2x13 Mixed Signal Microcontroller datasheet, the USCI UART and ADC10 interrupts have higher priority than the I/O Port pin interrupts.

    These priorities are fixed (as discussed here). According to Section 2.2.3.1 Interrupt Acceptance in the MSP430x2xx Family User's Guide, the interrupt logic executes as follows:

    1. Any currently executing instruction is completed.
    2. The PC, which points to the next instruction, is pushed onto the stack.
    3. The SR is pushed onto the stack.
    4. The interrupt with the highest priority is selected if multiple interrupts occurred during the last
    instruction and are pending for service.
    5. The interrupt request flag resets automatically on single-source flags. Multiple source flags remain set
    for servicing by software.
    6. The SR is cleared. This terminates any low-power mode. Because the GIE bit is cleared, further
    interrupts are disabled.
    7. The content of the interrupt vector is loaded into the PC: the program continues with the interrupt
    service routine at that address.

    If the ADC10 and Port 1 interrupts fire at the same time, the ADC10 ISR will get priority over the Port 1 ISR. However, when the ADC10 ISR is complete, the Port 1 ISR should be executed next. Like you mentioned, perhaps there's not enough time to get to the lower priority Port 1 ISR if either the higher priority USCI UART or ADC10 ISRs are always getting executed.

    David__ said:
    - Is there an option to enable the interrupt when the code is running the ISR?

    Yes, this is called "nested interrupts". According to Section 2.2.3.3 Interrupt Nesting in the user's guide, "interrupt nesting is enabled if the GIE bit is set inside an interrupt service routine. When interrupt nesting is enabled, any interrupt occurring during an interrupt service routine will interrupt the routine, regardless of the interrupt priorities".

    David__ said:
    - In this case, should I seperate the UART sending part from the ADC ISR and put it inside the main loop?

    Ideally, the ISRs should be as short as possible. However, I understand why you'd want to send the ADC data over UART inside the ADC10 ISR because it's inherently periodic. Otherwise, you would need to use a Timer to send the data over UART. I would make sure you're running at the highest CPU frequency to give you the most time between ADC10 samples. Also, there could be start-up time delays when coming out of LPM0 but this may be minimal compared to lower level modes like LPM3 - this is more crucial when trying to receive UART data at fast baud rates rather than just send the data.

    You could move the UART sending part to main() but it will still be calling the USCI UART ISR. Enabling interrupt nesting (assuming the available bandwidth isn't getting exceeded) should solve your issue. Just keep in mind that debouncing the switch is good but the delay for that may be much slower than 1/5kHz ADC sampling time.

    Regards,

    James

  • Further to what James wrote, it looks like your uart_tx function blocks until both bytes have been sent. Since the function transmits two bytes in the context of the ADC ISR with GIE cleared I guess uart_tx is polling the UART IFG to wait for completion of each byte. This would result in the port interrupt being delayed.

    The only way I can see this preventing the port ISR from ever being called is if the ADC completes another conversion before the UART transmission is complete. In that case the ADC ISR will be called again immediately each time it completes. The port ISR would then be starved due to the constantly-requested ADC interrupt, which has higher priority.

    I think you might want to look into having the ADC interrupt wake from LPM0, with the uart_tx call in the main loop. The port interrupt can then be handled during the UART transmission if the button is pressed. Also it would be good to check the rate of ADC conversions to make sure that they aren't happening faster than the results can be transmitted out.

    EDIT: Re-reading the specifications (5000Hz sample rate, 115200 baud), I think the input and output rates are pretty close. 115200 baud works out at 11520 bytes per second (assuming 8N1), so you can output at most 5760 ADC readings per second. That assumes the UART is transmitting continuously. For each sample you only have 26 microseconds spare, excluding the time the UART will take to output the data onto the wire.

**Attention** This is a public forum