Serial Wombat
a general-purpose digital interface device for hobbyists, engineers and students

 


Home
Overview
Protocol
Documentation
Channel Modes
Direct Control
Controlled Pin
Raw A/D
A/D Averaging
A/D 1st Order Filtering
Matrix Keypad
Servo Control
Analog Direct
Analog Follow
Rotary Encoder
Debouncing
Counter
Hysteresis
Morse Code
Pulse
Unipolar Stepper
LCD Driver 1
LCD Driver 2
HW Pulse Meas.
2D Lookup
SPI Master
HD44780 Generic
Remote Control
DataLogger
Min-Max
Public Data
Timed IO
Getting Started
Connectivity
Pin Mode SDK Beta
Sample Projects
Downloads
Contact Us
Purchase
Forum

Did you know...

 

Serial Wombat Hardware Transition Measurement Channel Mode

A few pins on the Serial Wombat have special hardware assisted features capable of measuring the timing between high to low and low to high transitions. These pins can accurately count and time transitions occuring as often as every 15 microseconds, and as infrequently as every two seconds. This channel mode was designed with two primary goals in mind: allowing the measurement of periodic events such as a position sensor on a rotating wheel or shaft, and allowing the measurement of standard R/C Servo pulse inputs from a receiver or other source.

This channel mode is different from most other Serial Wombat channel modes in that it only works on a few specific pins: 16, 17, 33, 34, and 35. These pins have special hardware which allows interrupts to occur upon a pin state transition. When this happens, the Wombat will stop what it's doing, capture a new timestamp corresponding to the time of the transition, increment a counter for that pin, and return to its prior work. This allows the Wombat firmware to be sufficently responsive to inputs while still maintaining the round-robin style pin scheduling used by the Serial Wombat executive.

When the host enables the Hardware Transition Measurement Channel Mode for one of the eligible pins, a high priority interrupt is enabled inside the Wombat for that pin. Any time this input pin changes state, a small amount of interrupt code will be executed at a higher priority than other tasks in the system.

This presents a potential problem for the system. If pin transitions occur faster than the Wombat's CPU core can process the interrupt code, then the Wombat will spend 100% of its time trying to record these transitions. This results in a situation where the rest of the Wombat firmware, including the Serial Port receive software which could otherwise be used to turn off this mode is starved. In order to avoid this situation, the system design should not allow pin transitions on pins using Hardware Transition Measurement to occur more often than every 15 microseconds. This applies to the summation of all pins which are enabled in this mode. This is to say that if all 5 eligible pins are enabled, on average, only one pin should transition every 15 microseconds.

Future versions of the Serial Wombat will include a user-enabled watchdog function which will reset the Wombat if the communications code is not serviced within some period of time (likely 1 to 2 seconds). This will disable all channel modes and allow the host to regain control in the event of a starvation event.

Even if these conditions are met, it is possible that under some circumstances transition interrupts may consume enough of the Wombat's CPU time to cause other tasks to run slowly. It is recommended that a throughput analysis be performed under realistic usage conditions to determine if the Wombat has sufficient CPU power to perform all desired tasks. Documentation on how to use the Wombat's internal CPU usage monitoring will be available in the future.

For each of the 5 pins the Wombat keeps transition timestamps of the two most recent high-to-low and low-to-high transitions. This allows the Wombat to provide period/frequency information, and durations for high and low sections of a wave form. This can be used to accurately measure the frequency and duty cycle of an incoming PWM signal. Each of these four times is stored as a 24-bit number. Each 'tick' of the time represents 1/16 of the clock used by the Serial Wombat. Therefore, the 32Mhz internal clock would yield a time of 500 nanoseconds. The absolute value of these timestamps has no meaning. However, by comparing timestamps of events which happen within 2 seconds of each other, relative timing can be determined.

Additonally, a counter is kept for each pin which counts the total number of transitions for that pin. This is a 16 bit value which will wrap around from 65535 to 0. This counter can be used by the host to determine if new timing data is available, and can be used to determine the average number of transitions over a period of time.

The Hardware Transition Measurement function can provide one of a number of different outputs as it's public data:

Output Value Meaning
Low Time 0 The elapsed time between the latest high-to-low and low-to-high transition pair. Units are 1 / 2,000,000ths of a second when the 32Mhz internal oscillator is used. Because the internal oscillator can vary by up to 1%, this value is only accurate to within 1%. If this value is longer than 65535 units, then 65535 units will be the public data.
High Time 1 The elapsed time between the latest low-to-high and high-to-low transition pair. Units are 1 / 2,000,000ths of a second when the 32Mhz internal oscillator is used. Because the internal oscillator can vary by up to 1%, this value is only accurate to within 1%. If this value is longer than 65535 units, then 65535 units will be the public data.
Low Period 2 The elapsed time between the last two high-to-low transitions. Units are 1 / 2,000,000ths of a second when the 32Mhz internal oscillator is used. Because the internal oscillator can vary by up to 1%, this value is only accurate to within 1%. If this value is longer than 65535 units, then 65535 units will be the public data.
High Period 3 The elapsed time between the last two low-to-high transitions. Units are 1 / 2,000,000ths of a second when the 32Mhz internal oscillator is used. Because the internal oscillator can vary by up to 1%, this value is only accurate to within 1%. If this value is longer than 65535 units, then 65535 units will be the public data.
Low Time / 256 4 Same as 0 above, but with units of 256 / 2,000,000ths of a second when the 32Mhz internal oscillator is used. This allows lower resolution timing but longer pulse durations. Durations of more than 2 seconds may cause internal mathematics overflows resulting in undefined behavior.
High Time / 256 5 Same as 1 above, but with units of 256 / 2,000,000ths of a second when the 32Mhz internal oscillator is used. This allows lower resolution timing but longer pulse durations. Durations of more than 2 seconds may cause internal mathematics overflows resulting in undefined behavior.
Low Period / 256 6 Same as 2 above, but with units of 256 / 2,000,000ths of a second when the 32Mhz internal oscillator is used. This allows lower resolution timing but longer pulse durations. Durations of more than 2 seconds may cause internal mathematics overflows resulting in undefined behavior.
High Period / 256 7 Same as 3 above, but with units of 256 / 2,000,000ths of a second when the 32Mhz internal oscillator is used. This allows lower resolution timing but longer pulse durations. Durations of more than 2 seconds may cause internal mathematics overflows resulting in undefined behavior.
Duty Cycle 8 Provides a value between 0 and 65535 representing the duty cycle of the input waveform. This value is updated only when a new transition comes in. Therefore, this duty cycle will not accurately represent 0% or 100% duty cycles, since they do not cause transitions.

 

 

Message format:

The first message is used to enable interrupts so that the special hardware on the selected pin can begin measuring transitions. This message also configures which aspect of the transition measurements is presented to the rest of the system as public data.

Data Sent to the Wombat: 200 Pin # 24 Public Data Output 0x55 0x55 0x55 0x55
Meaning: Configure Pin First message Pin Number to be set to HW Pulse measurement. Must be 16, 17, 33, 34, or 35 Hardware Transition Measurement Mode See table above for values and meanings Unused. Unused. Unused. Unused.
This message is echoed back by the Wombat.

 

The second message is used to retreive transition data. It is possible that the user may wish to retreive more than one set of data for a set of captured transitions. For this reason, the host can choose to suspend additional captures after the message is returned to the host. This allows, for example, the host to request both high and low times for the same set of 4 transitions, allowing a calculation of duty cycle. This is not possible if additional transtions are captured between requests. If the host is only interested in one piece of data, such as pulse high-time, then additional captures can be left enabled so that additional data is captured after the message is returned.

Data Sent to the Wombat: 201 Pin # 24 Requested data Continous Capture 0x55 0x55 0x55
Meaning: Configure Pin Second message Pin Number to be set to HW Pulse measurement. Must be 16, 17, 33, 34, or 35 Hardware transition measurement mode What Time Data is to be returned to the host:

0:Low Time
1: High Time
2: High-to-low Transition period
3: Low-to-high transition period

0: Stop capturing new transitions

1: Continue capturing new transitions

Unused Unused Unused.
Data Returned from the Wombat: 201 Pin # 24 Time Value MSB Time Value Middle Byte Time Value LSB Count MSB Count LSB
Meaning: Same as send Same as send Same as send This 24-bit value represents the time requested by the host. Units are 1 / 2,000,000 of a second when using the internal 32Mhz oscillator. Accuracy is +/- 1% due to variation in internal oscillator frequency. This 16-bit value is a running count of the number of transitions detected. This value can roll over from 65535 to 0 without notice.

 

 

Example:

 

Configure channel 16 to capture the high time of pulses. Then issue a command asking for the high time to be returned to the host, without pausing captures. Response will be for a high pulse of 0.7624 seconds, pulse number 4217

SEND to Wombat:
 200 16 24 1 0x55 0x55 0x55 0x55 ; Set pin 16 to Hardware Pulse Management mode,
                           ; Report high time as public data (1)
SEND to Wombat:
 201 16 24 1 1 0x55 0x55 0x55             ; Get High Time from Pin 16, don't pause
RESPONSE from Wombat:
201 16 24 0x17 0x44 0x40 0x10 0x79    ;  High time = 0x174440 = 1524800 = 2000000 * .7624
                                      ;  Count = 0x1079 = 4217

 

Pin Mode Source Code

The following code is what creates the pin mode for this function inside of the Wombat. You don't need to know this to use the pin mode, but some people find it interesting. See the SDK for some insight into how pin modes work. Hold your mouse over various words and variables for definitions. #include "utilities.h"
#include "global_data.h"
#pragma code APPLICATION
#pragma romdata APPLICATION_DATA

#define HW_PULSE_WIDTH_GET_LOW_TIME 0
#define HW_PULSE_WIDTH_GET_HIGH_TIME 1
#define HW_PULSE_WIDTH_GET_LOW_TRANS_PERIOD 2
#define HW_PULSE_WIDTH_GET_HIGH_TRANS_PERIOD 3
#define HW_PULSE_WIDTH_FREEZE 1 

#define HW_PULSE_WIDTH_PUBLIC_LOW_TIME 0
#define HW_PULSE_WIDTH_PUBLIC_HIGH_TIME 1
#define HW_PULSE_WIDTH_PUBLIC_LOW_PERIOD 2
#define HW_PULSE_WIDTH_PUBLIC_HIGH_PERIOD 3
#define HW_PULSE_WIDTH_PUBLIC_LOW_TIME_DIV_256 4
#define HW_PULSE_WIDTH_PUBLIC_HIGH_TIME_DIV_256 5
#define HW_PULSE_WIDTH_PUBLIC_LOW_PERIOD_DIV_256 6
#define HW_PULSE_WIDTH_PUBLIC_HIGH_PERIOD_DIV_256 7
#define HW_PULSE_WIDTH_PUBLIC_DUTY_CYCLE 8
void hw_pulse_width_load_data(void)
{

          if (virtual_pin == CCP1_VIRTUAL_PIN)
          {
                DISABLE_CCP1_CAPTURE();
                  tp2.hw_pulse_width.low.u = CCP1_LowCapture.u;
                  tp2.hw_pulse_width.high.u = CCP1_HighCapture.u;
                  tp.hw_pulse_width.oldhigh.u = CCP1_HighCaptureOld.u;
                  tp.hw_pulse_width.oldlow.u = CCP1_LowCaptureOld.u;
                 tp2.hw_pulse_width.count.u = CCP1_counter.u;
                 local_j = CCP1_LastEvent;
                if (tp.hw_pulse_width.enabled)
                {
                        ENABLE_CCP1_CAPTURE();
                }
                 tp.hw_pulse_width.last = local_j & 0x01;
          }
          else if (virtual_pin == CCP2_VIRTUAL_PIN)
          {
                DISABLE_CCP2_CAPTURE();
                  tp2.hw_pulse_width.low.u = CCP2_LowCapture.u;
                  tp2.hw_pulse_width.high.u = CCP2_HighCapture.u;
                  tp.hw_pulse_width.oldhigh.u = CCP2_HighCaptureOld.u;
                  tp.hw_pulse_width.oldlow.u = CCP2_LowCaptureOld.u;
                 tp2.hw_pulse_width.count.u = CCP2_counter.u;
                 local_j = CCP2_LastEvent;
                if (tp.hw_pulse_width.enabled)
                {
                        ENABLE_CCP2_CAPTURE();
                }
                 tp.hw_pulse_width.last = local_j & 0x01;
          }
          else if (virtual_pin == INT0_VIRTUAL_PIN)
          {
                DISABLE_INT0_CAPTURE();
                  tp2.hw_pulse_width.low.u = INT0_LowCapture.u;
                  tp2.hw_pulse_width.high.u = INT0_HighCapture.u;
                  tp.hw_pulse_width.oldhigh.u = INT0_HighCaptureOld.u;
                  tp.hw_pulse_width.oldlow.u = INT0_LowCaptureOld.u;
                 tp2.hw_pulse_width.count.u = INT0_counter.u;
                 tp.hw_pulse_width.last = INT0_LastEvent & 0x01;
                if (tp.hw_pulse_width.enabled)
                {
                        ENABLE_INT0_CAPTURE();
                }
          }
          else if (virtual_pin == INT1_VIRTUAL_PIN)
          {
                DISABLE_INT1_CAPTURE();
                  tp2.hw_pulse_width.low.u = INT1_LowCapture.u;
                  tp2.hw_pulse_width.high.u = INT1_HighCapture.u;
                  tp.hw_pulse_width.oldhigh.u = INT1_HighCaptureOld.u;
                  tp.hw_pulse_width.oldlow.u = INT1_LowCaptureOld.u;
                 tp2.hw_pulse_width.count.u = INT1_counter.u;
                 tp.hw_pulse_width.last = INT1_LastEvent & 0x01;
                if (tp.hw_pulse_width.enabled)
                {
                        ENABLE_INT1_CAPTURE();
                }
          }
          else if (virtual_pin == INT2_VIRTUAL_PIN)
          {
                DISABLE_INT2_CAPTURE();
                  tp2.hw_pulse_width.low.u = INT2_LowCapture.u;
                  tp2.hw_pulse_width.high.u = INT2_HighCapture.u;
                  tp.hw_pulse_width.oldhigh.u = INT2_HighCaptureOld.u;
                  tp.hw_pulse_width.oldlow.u = INT2_LowCaptureOld.u;
                 tp2.hw_pulse_width.count.u = INT2_counter.u;
                 local_j = INT2_LastEvent;
                if (tp.hw_pulse_width.enabled)
                {
                        ENABLE_INT2_CAPTURE();
                }
                 tp.hw_pulse_width.last = local_j & 0x01;
          }


          else
          {
                  error();
                  return;

          }
}

void hw_pulse_width_calc_low_time(void)
{
        local_temp32_1.bytes.h = 1;
        local_temp32_1.bytes.mh = tp2.hw_pulse_width.high.bytes.h;
        local_temp32_1.bytes.ml = tp2.hw_pulse_width.high.bytes.m;
        local_temp32_1.bytes.l = tp2.hw_pulse_width.high.bytes.l;
        if (tp.hw_pulse_width.last)
        {
                  local_temp32_1.u -= tp2.hw_pulse_width.low.u;
        }
        else
        {
                 local_temp32_1.u -= tp.hw_pulse_width.oldlow.u;
        }
    local_temp32_1.bytes.h = 0;
        return;
}

void hw_pulse_width_calc_high_time( void)
{
        local_temp32_1.bytes.h = 1;
          local_temp32_1.bytes.mh = tp2.hw_pulse_width.low.bytes.h;
          local_temp32_1.bytes.ml = tp2.hw_pulse_width.low.bytes.m;
          local_temp32_1.bytes.l = tp2.hw_pulse_width.low.bytes.l;
        if (tp.hw_pulse_width.last)
        {
                  local_temp32_1.u -= tp.hw_pulse_width.oldhigh.u;
        }
        else
        {
                  local_temp32_1.u -= tp2.hw_pulse_width.high.u;
        }
    local_temp32_1.bytes.h = 0;
    return;
}

void hw_pulse_width_calc_high_period(void)
{
        local_temp32_1.bytes.h = 1;
          local_temp32_1.bytes.mh = tp2.hw_pulse_width.high.bytes.h;
          local_temp32_1.bytes.ml = tp2.hw_pulse_width.high.bytes.m;
          local_temp32_1.bytes.l = tp2.hw_pulse_width.high.bytes.l;
          local_temp32_1.u -= tp.hw_pulse_width.oldhigh.u;
      local_temp32_1.bytes.h = 0;
      return;
}

void hw_pulse_width_calc_low_period(void)
{
        local_temp32_1.bytes.h = 1;
          local_temp32_1.bytes.mh = tp2.hw_pulse_width.low.bytes.h;
          local_temp32_1.bytes.ml = tp2.hw_pulse_width.low.bytes.m;
          local_temp32_1.bytes.l = tp2.hw_pulse_width.low.bytes.l;
          local_temp32_1.u -= tp.hw_pulse_width.oldlow.u;
      local_temp32_1.bytes.h = 0;
      return;
}



void init_hw_pulse_width(void)
{
        if (rxbuffer[0] == CONFIGURE_CHANNEL_MODE_0)
        {
                //Configure pin
          if (virtual_pin == CCP1_VIRTUAL_PIN)
          {
                  CCP1CON = 0x04;
                  T3CONbits.T3CCP2 = 1;

                  ENABLE_CCP1_CAPTURE();
          }
          else if (virtual_pin == CCP2_VIRTUAL_PIN)
          {
                  CCP2CON = 0x04;
                  T3CONbits.T3CCP2 = 1;
                  ENABLE_CCP2_CAPTURE();
          }
          else if (virtual_pin == INT0_VIRTUAL_PIN)
          {
                  ENABLE_INT0_CAPTURE();
                  INT0_mode = 2;
          }
          else if (virtual_pin == INT1_VIRTUAL_PIN)
          {
                  ENABLE_INT1_CAPTURE();
                  INT1_mode = 2;
          }
          else if (virtual_pin == INT2_VIRTUAL_PIN)
          {
                  ENABLE_INT2_CAPTURE();
                  INT2_mode = 2;
          }
          else
          {
                  error();
                  return;
          }
          vpin_input();
          tp.hw_pulse_width.mode = rxbuffer[3];
        }
        if (rxbuffer[0] == CONFIGURE_CHANNEL_MODE_1)
        {

                tp.hw_pulse_width.enabled = rxbuffer[4] > 0;

                hw_pulse_width_load_data();

                if (rxbuffer[3] == HW_PULSE_WIDTH_GET_LOW_TIME)
                {
                        hw_pulse_width_calc_low_time();

                }
                else if (rxbuffer[3] == HW_PULSE_WIDTH_GET_HIGH_TIME)
                {
                        hw_pulse_width_calc_high_time();
                }
                else if (rxbuffer[3] == HW_PULSE_WIDTH_GET_HIGH_TRANS_PERIOD)
                {
                        hw_pulse_width_calc_high_period();
                }
                else if (rxbuffer[3] == HW_PULSE_WIDTH_GET_LOW_TRANS_PERIOD)
                {
                        hw_pulse_width_calc_low_period();
                }

                  txbuffer[3] = local_temp32_1.bytes.mh;
                  txbuffer[4] = local_temp32_1.bytes.ml;
                  txbuffer[5] = local_temp32_1.bytes.l;
                  txbuffer[6] = tp2.hw_pulse_width.count.bytes.highbyte ;
                  txbuffer[7] = tp2.hw_pulse_width.count.bytes.lowbyte ;
          vpin_input();
        }

}

void update_hw_pulse_width (void)
{
        if (!tp.hw_pulse_width.enabled)
        {
                return;
        }
        if (tp.hw_pulse_width.mode == HW_PULSE_WIDTH_PUBLIC_DUTY_CYCLE)
        {
                hw_pulse_width_load_data();
                hw_pulse_width_calc_high_time();
                if (local_temp32_1.bytes.mh > 0)
                {
                        tp2.hw_pulse_width.local_temp32_2.bytes.h = local_temp32_1.bytes.mh;
                        tp2.hw_pulse_width.local_temp32_2.bytes.mh = local_temp32_1.bytes.ml;
                        tp2.hw_pulse_width.local_temp32_2.bytes.ml = local_temp32_1.bytes.l;
                        hw_pulse_width_calc_high_period();
                        local_temp32_1.bytes.l = local_temp32_1.bytes.ml;
                        local_temp32_1.bytes.ml = local_temp32_1.bytes.mh;
                        local_temp32_1.bytes.mh = 0;
                        local_temp32_1.bytes.h = 0;
                        tp.generic.buffer = tp2.hw_pulse_width.local_temp32_2.u / local_temp32_1.u;

                }
                else
                {
                        tp2.hw_pulse_width.local_temp32_2.bytes.h = local_temp32_1.bytes.ml;
                        tp2.hw_pulse_width.local_temp32_2.bytes.mh = local_temp32_1.bytes.l;
                        hw_pulse_width_calc_high_period();
  
                           tp.generic.buffer = tp2.hw_pulse_width.local_temp32_2.u / local_temp32_1.u;
                }

        }
        else if (tp.hw_pulse_width.mode == HW_PULSE_WIDTH_PUBLIC_HIGH_PERIOD)
        {
                hw_pulse_width_load_data();
                hw_pulse_width_calc_high_period();
                tp.generic.buffer =  local_temp32_1.u;


        }
        else if (tp.hw_pulse_width.mode == HW_PULSE_WIDTH_PUBLIC_LOW_PERIOD)
        {
                hw_pulse_width_load_data();
                hw_pulse_width_calc_low_period();
                tp.generic.buffer =  local_temp32_1.u;


        }
        else if (tp.hw_pulse_width.mode == HW_PULSE_WIDTH_PUBLIC_HIGH_PERIOD_DIV_256)
        {
                hw_pulse_width_load_data();
                hw_pulse_width_calc_high_period();
                tp.generic.buffer =  local_temp32_1.midword.u;


        }
        else if (tp.hw_pulse_width.mode == HW_PULSE_WIDTH_PUBLIC_LOW_PERIOD_DIV_256)
        {
                hw_pulse_width_load_data();
                hw_pulse_width_calc_low_period();
                tp.generic.buffer =  local_temp32_1.midword.u;


        }
        else if (tp.hw_pulse_width.mode == HW_PULSE_WIDTH_PUBLIC_HIGH_TIME)
        {
                hw_pulse_width_load_data();
                hw_pulse_width_calc_high_time();
                tp.generic.buffer =  local_temp32_1.u;


        }
        else if (tp.hw_pulse_width.mode == HW_PULSE_WIDTH_PUBLIC_LOW_TIME)
        {
                hw_pulse_width_load_data();
                hw_pulse_width_calc_low_time();
                tp.generic.buffer =  local_temp32_1.u;


        }
        else if (tp.hw_pulse_width.mode == HW_PULSE_WIDTH_PUBLIC_LOW_TIME_DIV_256)
        {
                hw_pulse_width_load_data();
                hw_pulse_width_calc_low_time();
                tp.generic.buffer =  local_temp32_1.midword.u;


        }
        else if (tp.hw_pulse_width.mode == HW_PULSE_WIDTH_PUBLIC_HIGH_TIME_DIV_256)
        {
                hw_pulse_width_load_data();
                hw_pulse_width_calc_high_time();
                tp.generic.buffer =  local_temp32_1.midword.u;


        }
        executive_settings.buffer_dirty = 1;

}


Support code

The following assembly code is the high-priority interrupt that generates the interrupt based data for consumption by the C code.         LIST P=18F4620
        #include <P18F4620.INC>        ; File contains addresses for register and bit names
APPLICATION_CODE CODE 

        EXTERN timer3U;
        EXTERN INT0_counter;
        EXTERN INT0_HighCaptureOld;
        EXTERN INT0_LowCaptureOld;
        EXTERN INT0_HighCapture;
        EXTERN INT0_LowCapture;
        EXTERN INT0_mode;
        EXTERN INT0_LastEvent;
        EXTERN INT0_counter;
        EXTERN INT1_counter;
        EXTERN INT1_HighCaptureOld;
        EXTERN INT1_LowCaptureOld;
        EXTERN INT1_HighCapture;
        EXTERN INT1_LowCapture;
        EXTERN INT1_mode;
        EXTERN INT1_LastEvent;
        EXTERN INT1_counter;

        EXTERN INT2_HighCaptureOld;
        EXTERN INT2_LowCaptureOld;
        EXTERN INT2_HighCapture;
        EXTERN INT2_LowCapture;
        EXTERN INT2_mode;
        EXTERN INT2_LastEvent;
        EXTERN INT2_counter;
     EXTERN INT1_counter;
     EXTERN CCP1_counter;
     EXTERN CCP1_LowCapture;
     EXTERN CCP1_HighCapture;
     EXTERN CCP1_LowCaptureOld;
     EXTERN CCP1_HighCaptureOld;
     EXTERN CCP1_LastEvent;
     EXTERN FSR0L_TEMP;
     EXTERN FSR0H_TEMP;

     EXTERN CCP2_counter;
     EXTERN CCP2_LowCapture;
     EXTERN CCP2_HighCapture;
     EXTERN CCP2_LowCaptureOld;
     EXTERN CCP2_HighCaptureOld;
     EXTERN CCP2_LastEvent;
     EXTERN TMR1_PORTB_counter;
     EXTERN TMR1_PORTB_counter_max;
     EXTERN TMR1_UPDATE_H;
     EXTERN TMR1_UPDATE_L;
         EXTERN ENABLE_TMR1_WRITE

     EXTERN Interrupt_Occurred

high_priority_interrupt
        POP                     ;  Hack to get the  fast interrupt working right
        MOVLB timer3U;             Set the bank to the interrupt variable space

        BSF Interrupt_Occurred,0,1  ;  Let the app know that an interrupt
                                    ; occurred.  This is necessary if you want
                                    ; to monitor in a loop based delay

        BTFSC PIE1, TMR1IE          ;  Check if it was the timer interrupt
        BTFSS PIR1, TMR1IF
        BRA TMR1IF_END              ;  Nope.
        ; Update timer here
        MOVF TMR1L, 0, 0            ; // Read here
        ADDWF TMR1_UPDATE_L, 0, 1   ; 
        MOVWF FSR0H_TEMP, 1         ;
        MOVF TMR1_UPDATE_H, 0, 1    ;
        ADDWF TMR1H, 1, 0           ;
        MOVF FSR0H_TEMP, 0, 1       ; 
        MOVWF TMR1L, 0              ; 6 // 6 instructions pass...
                                    ;  Reset the timer
                BCF PIR1, TMR1IF, 0

        MOVFF FSR0L, FSR0L_TEMP     ;  We're gonna use indexed addressing here
        MOVFF FSR0H, FSR0H_TEMP     ;  So keep copy of current address
        LFSR  FSR0, 0x600           ;  MAGIC NUM!  Address where User array starts
        MOVFF   TMR1_PORTB_counter,FSR0L  ;  Move the index we want to store
        MOVFF PORTB, INDF0                ;  Capture Port B into array
        INCF  FSR0H, 1, 0                 ;  Move to 0x700 array
        BTFSC ENABLE_TMR1_WRITE,0, 1      ;  Check to see if timed writes enabled
        MOVFF INDF0, LATB                 ; If so, write data to Port B
        INCF  TMR1_PORTB_counter,1,1      ;  Increment the counter for next time
        MOVF  TMR1_PORTB_counter,0,1      ;  Is it bigger than max?
        SUBWF TMR1_PORTB_counter_max, 0,1
        BTFSS STATUS,C
        CLRF  TMR1_PORTB_counter, 1       ; If so, clear it

        MOVFF FSR0L_TEMP, FSR0L           ;  Restore FSRs before leaving
        MOVFF FSR0H_TEMP, FSR0H
        RETFIE FAST
TMR1IF_END
        

        BTFSC PIE1, CCP1IE                  ;  Check if it's the CCP1 interrupt
        BTFSS PIR1, CCP1IF                  ; 
        BRA CCP1IF_END                      ;  Nope...
        INFSNZ CCP1_counter, 1, 1 ; Increment Increment CCP1_Counter Low, access
        INFSNZ CCP1_counter+1,1, 1 ; Increment Increment CCP1_Counter mid high, access
        NOP
        BTFSS CCP1CON,0, 0      ;  High to Low capture?
        BRA HIGH_TO_LOW_CCP1    ;  Nope...
        
        ;Move High Capture to Old High Capture
        MOVFF CCP1_HighCapture, CCP1_HighCaptureOld
        MOVFF CCP1_HighCapture + 1, CCP1_HighCaptureOld + 1
        MOVFF CCP1_HighCapture + 2, CCP1_HighCaptureOld + 2
        ; Then put the current time stamp into High Capture.
        MOVFF timer3U, CCP1_HighCapture+2 
        MOVFF CCPR1H, CCP1_HighCapture + 1 
        MOVFF CCPR1L, CCP1_HighCapture ;

        ;  Test to see if Timer 3 rolled over while we were doing the above
        ;  processing.  If so, top 8 bits of 24 might be too small
        BTFSS PIR2, TMR3IF, 0
        BRA CCP1_NO_TMR3_OVERFLOW   ;Nope
        TSTFSZ CCPR1H, 0      ;Yes.  Only matters if  CCP1 had just rolled over too
        BRA CCP1_NO_TMR3_OVERFLOW ;  Nope
        INCF CCP1_HighCapture + 2, 1, 1 ;  Add 1 to High Capture high byte

CCP1_NO_TMR3_OVERFLOW
        BCF PIE1, CCP1IE, 0   ;  Disable interrupt while changing trigger
        CLRF CCP1CON, 0      ;  Set for Falling Transition.
        MOVLW 0x04 ; Falling Transition
        MOVWF CCP1CON,0;
        BSF CCP1_LastEvent , 0 , 1 ;   ;  Last event was Low To High
        BCF PIR1, CCP1IF, 0    ;  Clear the flag
        BSF PIE1, CCP1IE, 0    ; reenable the interrupt.
        RETFIE FAST

HIGH_TO_LOW_CCP1
        ; Parallels HighCapture
        MOVFF CCP1_LowCapture, CCP1_LowCaptureOld
        MOVFF CCP1_LowCapture + 1, CCP1_LowCaptureOld + 1
        MOVFF CCP1_LowCapture + 2, CCP1_LowCaptureOld + 2
        MOVFF timer3U, CCP1_LowCapture+2 
        MOVFF CCPR1H, CCP1_LowCapture + 1 
        MOVFF CCPR1L, CCP1_LowCapture ;


CCP1_NO_TMR3_OVERFLOW_H2L
        BCF PIE1, CCP1IE, 0
        CLRF CCP1CON,0
        MOVLW 0x05 ; Rising Transition
        MOVWF CCP1CON,0;
        BCF CCP1_LastEvent , 0 , 1 ;
        BCF PIR1, CCP1IF, 0
        BSF PIE1, CCP1IE, 0
        RETFIE FAST
        
CCP1IF_END

        BTFSC PIE2, CCP2IE   ;11
        BTFSS PIR2, CCP2IF   ;13
        BRA CCP2IF_END       ;14

        INFSNZ CCP2_counter, 1, 1 ; Increment CCP2 Low Counter, access
        INFSNZ CCP2_counter+1,1, 1 ; Increment CCP2 high Counter, access
        NOP
        BTFSS CCP2CON,0   
        BRA HIGH_TO_LOW_CCP2
        
        MOVFF CCP2_HighCapture, CCP2_HighCaptureOld
        MOVFF CCP2_HighCapture + 1, CCP2_HighCaptureOld + 1
        MOVFF CCP2_HighCapture + 2, CCP2_HighCaptureOld + 2
        MOVFF timer3U, CCP2_HighCapture+2 
        MOVFF CCPR2H, CCP2_HighCapture + 1 
        MOVFF CCPR2L, CCP2_HighCapture ;
        BSF CCP2_LastEvent , 0 ;
        BTG CCP2CON, 0
        BCF PIR2, CCP2IF 
        RETFIE FAST
HIGH_TO_LOW_CCP2
        MOVFF CCP2_LowCapture, CCP2_LowCaptureOld
        MOVFF CCP2_LowCapture + 1, CCP2_LowCaptureOld + 1
        MOVFF CCP2_LowCapture + 2, CCP2_LowCaptureOld + 2
        MOVFF timer3U, CCP2_LowCapture+2 
        MOVFF CCPR2H, CCP2_LowCapture + 1 
        MOVFF CCPR2L, CCP2_LowCapture ;

        BTFSS PIR2, TMR3IF, 0
        BRA CCP2_NO_TMR3_OVERFLOW
        TSTFSZ CCPR2H, 0
        BRA CCP2_NO_TMR3_OVERFLOW
        INCF CCP2_HighCapture + 2, 1, 1

CCP2_NO_TMR3_OVERFLOW
        BCF CCP2_LastEvent , 0 ;
        BTG CCP2CON, 0
        BCF PIR2, CCP2IF  
        RETFIE FAST
        
CCP2IF_END

        BTFSC INTCON, INT0IE  ; 16
        BTFSS INTCON, INT0IF ; 18
        BRA INT0_END          ; 19
        BCF INTCON, INT0IF
        INFSNZ INT0_counter, 1, 1 ; Increment INT0_counter high, access
        INFSNZ INT0_counter+1,1, 1 ; Increment INT0_counter low, access
        NOP
        BTFSS INTCON2,INTEDG0    ; Check to see which trans was set
        BRA   INT0_HIGH_TO_LOW
           ;Process Low To High Interrupt
           MOVFF INT0_HighCapture, INT0_HighCaptureOld;
           MOVFF INT0_HighCapture + 1, INT0_HighCaptureOld + 1;
           MOVFF INT0_HighCapture + 2, INT0_HighCaptureOld + 2;
           MOVFF TMR3L, INT0_HighCapture ;
           MOVFF TMR3H, INT0_HighCapture + 1 ;
           TSTFSZ TMR3H, 0
           BRA INT0_LOW_TO_HIGH_NO_ADJ
           RCALL TMR3IF_OVERFLOW_ADJ 
INT0_LOW_TO_HIGH_NO_ADJ
           MOVFF timer3U, INT0_HighCapture + 2;
           BSF INT0_LastEvent, 0
           BTFSC INT0_mode,1; 
           BTG INTCON2,   INTEDG0, 0
        RETFIE FAST
INT0_HIGH_TO_LOW
           ;Process High to Low Interrupt
           MOVFF INT0_LowCapture, INT0_LowCaptureOld;
           MOVFF INT0_LowCapture + 1, INT0_LowCaptureOld + 1;
           MOVFF INT0_LowCapture + 2, INT0_LowCaptureOld + 2;
           MOVFF TMR3L, INT0_LowCapture ;
           MOVFF TMR3H, INT0_LowCapture  + 1;
           TSTFSZ TMR3H, 0
           BRA INT0_HIGH_TO_LOW_NO_ADJ
           RCALL TMR3IF_OVERFLOW_ADJ 
INT0_HIGH_TO_LOW_NO_ADJ
           MOVFF timer3U, INT0_LowCapture + 2;
           BCF INT0_LastEvent, 0
           BTFSC INT0_mode,1; 
           BTG INTCON2,   INTEDG0, 0
        RETFIE FAST

TMR3IF_OVERFLOW_ADJ
          BTFSS PIR2, TMR3IF, 0
          RETURN
          INCF timer3U, 1, 1
          bcf PIR2, TMR3IF, 0
          RETURN
 

INT0_END
 ;20
        BTFSC INTCON3, INT1IE ; 21
        BTFSS INTCON3, INT1IF ; 23
        BRA INT1_END          ; 24
        BCF INTCON3, INT1IF
        INFSNZ INT1_counter, 1, 1 ; Increment INT1_counter high, access
        INFSNZ INT1_counter+1,1, 1 ; Increment INT1_counter low, access
        NOP
        BTFSS INTCON2,INTEDG1    ; Check to see which trans was set
        BRA   INT1_HIGH_TO_LOW
           ;Process Low To High Interrupt
           MOVFF INT1_HighCapture, INT1_HighCaptureOld;
           MOVFF INT1_HighCapture + 1, INT1_HighCaptureOld + 1;
           MOVFF INT1_HighCapture + 2, INT1_HighCaptureOld + 2;
           MOVFF TMR3L, INT1_HighCapture ;
           MOVFF TMR3H, INT1_HighCapture + 1 ;
           TSTFSZ TMR3H, 0
           BRA INT1_LOW_TO_HIGH_NO_ADJ
           RCALL TMR3IF_OVERFLOW_ADJ 
INT1_LOW_TO_HIGH_NO_ADJ
           MOVFF timer3U, INT1_HighCapture + 2;
           BSF INT1_LastEvent, 0
           BTFSC INT1_mode,1; 
           BTG INTCON2,   INTEDG1
        RETFIE FAST
INT1_HIGH_TO_LOW
           ;Process High to Low Interrupt
           MOVFF INT1_LowCapture, INT1_LowCaptureOld;
           MOVFF INT1_LowCapture + 1, INT1_LowCaptureOld + 1;
           MOVFF INT1_LowCapture + 2, INT1_LowCaptureOld + 2;
           MOVFF TMR3L, INT1_LowCapture ;
           MOVFF TMR3H, INT1_LowCapture  + 1;
           TSTFSZ TMR3H, 0
           BRA INT1_HIGH_TO_LOW_NO_ADJ
           RCALL TMR3IF_OVERFLOW_ADJ 
INT1_HIGH_TO_LOW_NO_ADJ
           MOVFF timer3U, INT1_LowCapture + 2;
           BCF INT1_LastEvent, 0
           BTFSC INT1_mode,1; 
           BTG INTCON2,   INTEDG1
        RETFIE FAST
INT1_END

        BTFSC INTCON3, INT2IE ; 21
        BTFSS INTCON3, INT2IF ; 23
        BRA INT2_END          ; 24
        BCF INTCON3, INT2IF
        INFSNZ INT2_counter, 1, 1 ; Increment INT2_counter high, access
        INFSNZ INT2_counter+1,1, 1 ; Increment INT2_counter low, access
        NOP
        BTFSS INTCON2,INTEDG2    ; Check to see which trans was set
        BRA   INT2_HIGH_TO_LOW
           ;Process Low To High Interrupt
           MOVFF INT2_HighCapture, INT2_HighCaptureOld;
           MOVFF INT2_HighCapture + 1, INT2_HighCaptureOld + 1;
           MOVFF INT2_HighCapture + 2, INT2_HighCaptureOld + 2;
           MOVFF TMR3L, INT2_HighCapture ;
           MOVFF TMR3H, INT2_HighCapture + 1 ;
           TSTFSZ TMR3H, 0
           BRA INT2_LOW_TO_HIGH_NO_ADJ
           RCALL TMR3IF_OVERFLOW_ADJ 
INT2_LOW_TO_HIGH_NO_ADJ
           MOVFF timer3U, INT2_HighCapture + 2;
           BSF INT2_LastEvent, 0
           BTFSC INT2_mode,1; 
           BCF INTCON2,   INTEDG2
        RETFIE FAST
INT2_HIGH_TO_LOW
           ;Process High to Low Interrupt
           MOVFF INT2_LowCapture, INT2_LowCaptureOld;
           MOVFF INT2_LowCapture + 1, INT2_LowCaptureOld + 1;
           MOVFF INT2_LowCapture + 2, INT2_LowCaptureOld + 2;
           MOVFF TMR3L, INT2_LowCapture ;
           MOVFF TMR3H, INT2_LowCapture  + 1;
           TSTFSZ TMR3H, 0
           BRA INT2_HIGH_TO_LOW_NO_ADJ
           RCALL TMR3IF_OVERFLOW_ADJ 
INT2_HIGH_TO_LOW_NO_ADJ
           MOVFF timer3U, INT2_LowCapture + 2;
           BCF INT2_LastEvent, 0
           BTFSC INT2_mode,1; 
           BSF INTCON2,   INTEDG2
        RETFIE FAST
        
INT2_END


  ; 30
        BTFSS PIR2, TMR3IF   ;31
        BRA TMR3IF_END       ;32
        BCF PIR2,TMR3IF      
        INCF timer3U, 1, 1 ; Increment timer 3 high, access
        RETFIE FAST
TMR3IF_END
        RETFIE FAST



        
  

        global high_priority_interrupt
        
        END

 

Copyright Wombat Interface Products, 2005-2008. All Rights Reserved.