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.

Input capture with overflows

Other Parts Discussed in Thread: MSP430F2272

Greetings,

 

I am trying to measure a 1Hz signal to the full resolution of the 16MHz clock on a MSP430F2272. My code looks like this (I have omitted the setup, which I got Grace to do for me anyway).

 

uint16_t ovf_counter;
uint32_t prev_a;
uint32_t period_a;

int main(int argc, char *argv[]) {
    CSL_init();                     // Activate Grace-generated configuration
    ovf_counter = 0;
    prev_a = 0;
    period_a = 0;
   
    __enable_interrupt();           // Set global interrupt enable
   
    sciPrintf("\nPPS pulse comparator.\n\n");
   
    while(1) {
        if(period_a) {
            printf("A: %lu\n", period_a);
            period_a = 0;
        }
    }
}

void intrTaComp0(void) {
    const uint32_t t = (((uint32_t)ovf_counter) << 16) | TACCR0;
    period_a = t - prev_a;
    prev_a = t;
}   
void intrTAOvf(void) {
    ++ovf_counter;
    P1OUT ^= 1;
}

As you can see I count overflows in one handler, and handle captures with the other. However, every so often, a period reading is exactly 1 overflow period out. I think that this is because the capture interrupt is running after an overflow but before the overflow interrupt handler has incremented the overflow counter. How can I check if there is a pending non-handled overflow interrupt? There isn't a specific flag for it, as TAIFG is shared between CCR1, CCR2 and OVF.

 

 

  • Hi,

    First of all, using one capture interrupt and one overflow interrupt cannot work! How should you know if the overflow interrupt was already executed if you get a low value capture result?

    I remember that I have done something like this some years ago. I suggest to use two interrupts: one overflow (0x10000) and one at the half of the period (compare to 0x8000). So you get two "overflow counters". And depending on your captured value you can choose, let's say:

    0x0000..0x3FFF: you do not know if the real overflow isr was executed, take the half period value
    0x4000..0xAFFF: take the real overflow counter (0x4000 ticks safety)
    0xB000..0xFFFF: take the half period value (0x4000 ticks safety again)

    I think this should work.

    Best regards and good luck
    Edwin Krasser

  • Maybe I'm getting the wrong idea, but I see 2 possibilities:

    First you can enable nested interrupts in your capture interrupt (set GIE at the beginning) - which will allow the overflow interrupt to be serviced in any case. This is potentially dangerous as infinitely nested interrupts may occur and thus a stack overflow and other bad things can happen. So avoid this unless you can guarantee that all interrupts return fast enough to prevent infinite nesting.

    Second you are using the CCR0 for capturing (if I'm not mistaken). Now the CCR0 has it's own interrupt vector - meaning you can check TAIFG to see if CCR1, CCR2 or OVF were triggered. Problem is you can't decide which one it triggered (if you are using all of them). For that you can use the TAIV. It will tell you which source triggered the TAIFG.

    Now a read from TAIV will clear the highest priority flag and you cannot write to it. So basically if you check your TAIV it will alter the behavior of the other interrupts - so maybe it would be best to handle all the TAIV interrupts manually. Like checking the TAIV, execute the same method as in the ISR for that source, check it again, until TAIV is empty and all interrupt sources are handled.

    I've never done it, just something which came to my mind, I don't know if it will work like expected.

  • Hi,

    These are some good ideas, but as i already said: It cannot work. Well, perhaps it will work for hours or days, but there will be wrong results. Ok, it can work, but only if you have got an interrupt queue (Do uCs exist which have got something like this? And even then: What happens if both events occur in the same clock cycle?).

    Well, let's assume that the capture occurs near the overflow and the uC cannot handle the interrupts immediately (e.g. ISRs are disabled for a short time or another ISR must be served or whatever).

    1.) The capture has higher priority. When you capture a low timer value you will not know if the overflow ISR was executed before or not.
    2.) The capture has lower priority. When you capture a very high value near 0xFFFF you will not know if the overflow ISR was executed before or not.

    => It's a no-win situation.

    Best regards
    Edwin Krasser

  • I actually don't quite understand. The MSP interrupt architecture like I understood it (maybe I have a serious flaw in that):

    If an interrupt occurs (and GIE is set etc.) the corresponding interrupt service routine will be executed (that is the code at the interrupt vector will be executed). If multiple interrupts occur the one with the highest priority (device dependent) will be executed first, after servicing that request the next highest priority interrupt will be handled until all interrupts were serviced. You can check in software for any interrupt source using corresponding flags and interrupt vectors.

    So the timer A operation the capture registers have a higher priority than the overflow registers. That is if both are set at the same time, the capture interrupt will be served first.

    If the capture interrupt is serviced and it checks the other flags/interrupt vectors it can determine if the overflow interrupt was already handled or not - because the flag would have been reset if the overflow interrupt was executed before.

    Now I can see a problem if the capture occurs at a very high count - so that the delay in servicing the interrupt will be enough to also trigger the overflow (LPM wakeup + 6 cycles delay + some cycles to check the flags), that way it will think the overflow was not serviced before and will increase the overflow counter, but in fact the overflow occurred after the capture - so you will get a wrong overflow (+1) in that case.

    You can counter that with the knowledge about the delay and can tell if the capture is bigger than 0xFFF0 (value has to be determined based on delay and clock speeds)  the not handled overflow will be a false positive.

     

    You will of course always get in trouble if something delays your ISR execution by more than a complete cycle of the counter - but then you have a general problem with interrupt responsiveness in your system. But then it might be possible (like you suggested) to use another CCRx register and there you can check for the COV so you can see if you missed an entire cycle or not.

    So that's my thoughts but maybe I'm getting it all wrong because of false assumptions.

  • Edwin Krasser's suggested method is a good one. It is simple and works.

    Bernhard Weller's analysis of of the problem is only partially right and did not provide a solution. The interrupt latency cannot be easily predicted even if you use assembly code and know what you are doing.


  • Bernhard, imagine a capture interrupt happening at 0x8000. But right now, the MSP is executing a different ISR, or is in a critical section that has disabled interrupts.
    Now the overflow comes.

    When the currently executed ISR or the critical section ends, how do you knwo which of  the two pending interrupts (capture/overflow) happened first?
    Depending on your guess (with 50% chance to be the wong one) you'll be one cycle early or late.

    One possible solution is to chain two timers, using CCR0 PWm of the firs ttimer to clock the second one (external connection needed). When a capture happens, it will trigger a CCR unit on both timers and you'll get an exact 32 bit timer count.

  • Well okay yes. If your timer ISR responsiveness is in the order of half a cycle, you will run into trouble - but the method provided by Edwin won't help in that case either or am still failing to see the genius thing about that method?

    Consider the MSP being busy, the half period overflow interrupt is triggered but not served, then somewhere between 0xAFFF and 0xFFFF your capture happens, the MSP gets back to the timer ISR and you have the same problem again - two ISR and the end result of one depends on whether the other was executed or not.

    So basically there is no bulletproof software method - no matter how many interrupts you use, as there is no interrupt FIFO queue?

    If you can assure a certain responsiveness of the ISRs then you can make an educated guess on the timeline of the events thus leading to a better chance of guessing right?

  • Hi,

    Well, I consider the MSP as busy and the half period interrupt (at 0x8000) as not served. And I get a capture of >=0xB000. Of course, this will not work.

    But, we are talking about 0x4000 (>16000) clock cycles time (> 1ms at 16 MHz => frequency approx 1 KHz) for the execution of the very short half and full period interrupts. Well this should be possible to guarantee (e.g. you need this for a 9600 baud UART communication). Otherwise you should think about your software design.

    Cascading two 16-bit counters to one 32-bit counter using an external connection might be a sensible solution. But I do not know what the uC is doing exactly when getting the edge from the lower 16-bit counter (clock synchronization?). What happens when both edges happen at once? I do not know, perhaps some MSP experts know what's happening exactly.

    Hence I suggested a half and full period system, which is hundred percent software and has just an easy timing requirement to fulfill.

    Best regards,
    Edwin Krasser

  • I once replied: "Edwin Krasser's suggested method is a good one. It is simple and works."

    I still think that was a fair statement. But I would not call the compare=0x8000 counter "half period". Just like the Timer Overflow counter, it is also "full period". They both count once every 0x10000 cycles. When the capture=external-signal happens near 0x0000, you can use the compare=0x8000 counter. When the capture=external-signal happens near 0x8000, you can use the overflow counter. In both cases, you do not need to worry about the racing between the capture and the period counter.



**Attention** This is a public forum