-2

I'm currently working with 9S12 from freescale, I really need some help in order to understand how to write correctly an ISR. In particular, I'm reporting the text of an exercise in which they asked me to measure the difference in phase between two square waveforms (at the input of the microcontroller).

The bus clock is 16 MHz and I have to use the timer module of the system, which provides a free-running counter (TCNT @ 16 bit). The counter have to work @ 500 kHz, that is achieved by setting a prescaler of 5, starting from the bus clock. The two signals have the same frequency, which is given (25 Hz), but is required to measure it anyway.

I have to use the INTERRUPT procedure, using the correct registers (actually is not necessary using the exact same ones from the manual, I can use any names I want, instead I have to comment every line of the code) and variables.

My way of approaching the problem is very theoretical, but I need the C code.

In order to solve the problem I have to use the INPUT CAPTURE MODE, to measure the difference in term of units counted by the TCNT (TICKS) between the positive edge of signal 1 and the positive edge of signal 2. My doubts are in particular on the variables that I have to use, the type (LOCAL, GLOBAL, UNSIGNED, LONG (?)), how can I update the values correctly in the ISR and if I should take into account of the overflows of the counter and the respective interrupts generated by them.

I'm stuck in this problem, I hope someone can help me with some code examples in particular for the variables that I have to use and how to write the actual ISR. Thank you to everyone!

Lundin
  • 195,001
  • 40
  • 254
  • 396
218141
  • 35
  • 1
  • 5
  • Asking for code without making an attempt is somewhat bad form. SO is not a homework service. – Clifford Aug 22 '18 at 21:52
  • 1
    The register names should be provided by a vendor or toolchain supplied header file. Inventing your own would be insane - as is commenting _every_ line of code; you tend to end up with code like: `x = 1 ; // set x to 1` , which serves no useful purpose. Individual lines of code only make semantic sense in the context in which they exist, and well chosen symbol names can make much of the code self-documenting such that any useful comment would only state what is already obvious. Micro-commenting can be worse than no commenting, and is hard to maintain. – Clifford Aug 22 '18 at 22:36

2 Answers2

2

Treat the following as pseudo-code; it is for you to wade through the datasheet to determine how to configure and access the timer-capture unit - I am not familiar with the specific part

In general, given the timer-counter is 16 bit:

volatile static uint16_t phase_count = 0 ;
volatile static uint16_t mean_period_count = 0 ; 

int phasePercent()
{
    (phase_count * 100) / mean_period_count ;
}

int frequencyHz()
{
    500000 / mean_period_count ;
}

void TimerCounterISR( void )
{
    static uint16_t count1 = 0 ;
    static uint16_t count2 = 0 ;
    static uint16_t period1 = 0 ;
    static uint16_t period2 = 0 ;

    uint16_t now = getCaptureCount() ;

    if( isSignal1Edge() )
    {
        period1 = now - count1 ;
        count1 = now ;
    }
    else if( isSignal2Edge() )
    {
        period2 = now - count2 ;
        count2 = now ;

        phase_count = period2 - period1 ;
    }

    mean_period_count = (period1 + period2) >> 1 ;
}

The method assumes an up-counter and requires that the counter reload runs the full 16 bit range 0 to 0xFFFF - otherwise the modulo-216 arithmetic will not work, and the solution will be much more complex. For a down-counter, swap the operands in the period calculations.

Note the return value from phasePercent() and frequencyHz() will not be valid until after a complete rising-edge to rising-edge cycle on both phases. You could add an edge count and validate after the rising edge has been seen twice on each signal if that is an issue.

Clifford
  • 88,407
  • 13
  • 85
  • 165
  • Thank you!! now it's clear, but if I'm using unisgned variables, should I take consideration of the overflow of the counter? – 218141 Aug 25 '18 at 09:41
  • @218141 No, that is what my point about modulo 2^16 arithmetic refers to. The event interval merely needs to be less than the timer reload cycle time. – Clifford Aug 25 '18 at 10:05
1

This is how you sort out the technical parts for the S12:

  • Setup the ECT timer with appropriate pre-scaler. You seem to have this part covered? At 500kHz each timer tick is 2us and you need 65536 timer ticks to cover the worst case. One full TCNT period will be 131ms with your prescaler. If ~25Hz is the worst case, then that's roughly 40ms so it should be ok in that case.

  • Pick a timer channel TC that corresponds to the pin used. This channel needs to be configured as input capture, trigger on both rising/falling edge. Store the current value of TCNT as init value to a uint16_t time counter variable.

  • Register the ISR in the vector table etc, the usual stuff for writing an ISR.

  • Upon interrupt, read the value of the TCn channel register. The difference between the counter variable and the stored value gives the period time in timer cycles. Multiply this with 1/500kHz and you get the period time. In the ISR always read TC and not TCNT, as the former will not be affected by interrupt latency and code execution overhead. Update your counter variable with the value from TCn.

  • With a design like this ensure there are some external means of filtering out spikes and EMI from the input: RC filter or similar.

Lundin
  • 195,001
  • 40
  • 254
  • 396