Output Compare SW Block Icon
The MCHP_OC_SW block provides interrupt-driven software output compare functionality. Unlike hardware OC which operates autonomously, this block uses timer interrupts to precisely time output pin changes, offering greater flexibility at the cost of CPU overhead.

The MCHP_OC_SW block provides interrupt-driven software output compare functionality. Unlike hardware OC which operates autonomously, this block uses timer interrupts to precisely time output pin changes, offering greater flexibility at the cost of CPU overhead.

Key Features

  • Interrupt-driven timing - Software updates output pins via timer interrupts
  • Multiple operational modes - Up/Down edges, Period control, Toggle
  • Dynamic timing changes - Frequency and duty cycle adjustable at runtime
  • Automatic timer allocation - Uses MCHP_Fun.TimerConfig() for resource management
  • Flexible pin mapping - Works with any GPIO pin (not limited to OC pins)
  • Period input support - Dynamic frequency control via Simulink signal

Comparison: OC_HW vs OC_SW

FeatureMCHP_OC_HWMCHP_OC_SW
CPU OverheadNone (autonomous)Interrupt per edge transition
FlexibilityFixed modes (3, 5, 6, 7)More modes (3, 5, 10, 32)
Pin AssignmentOC pins only (or PPS)Any GPIO pin
Dynamic ChangesGlitch-free duty cycleFull runtime reconfiguration
Best ForHigh-frequency PWM, motor controlFlexible timing, variable frequency

Device Support

Device FamilyTimer ResourcesNotes
dsPIC30F/33FType A/B timersAutomatic allocation
dsPIC33EType A/B/C timersEnhanced timer features
dsPIC33C/CH/CKType A/B timersHigh-speed timer option
dsPIC33AType A/B timersModern timer architecture
PIC24Type A/B/C timersStandard operation
PIC3232-bit timersHigher resolution available

Block Parameters

Channel Configuration

ParameterDescriptionValues
ChannelOC channel identifiers to use1-9 (logical channels, not hardware OC)
Channel_UP_Down_PeriodeOperation mode per channel3 (Up & Down)
InputPeriodPeriod source‘is a block input’ - Dynamic via Simulink
PIN_OCxGPIO pin assignmentAny available GPIO (e.g., ‘RA0’, ‘RB5’)
Timer ConfigurationAutomatic timer allocationHandled by MCHP_Fun.TimerConfig()

Operational Modes

ModeDescriptionBlock InputsUse Case
3Up & Down edgesOC1_Up (rising time)OC1_Down (falling time)
5Up edge & PeriodOC1_Up (pulse width)OC1_Per (period, optional)
10Down edge & PeriodOC1_Down (pulse width)OC1_Per (period, optional)
32Toggle modeOC1_Toggle (half period)Square wave generation, clock output

Implementation Details

Software Algorithm

// Interrupt-driven output compare (Mode 3 example)
void __attribute__((__interrupt__, no_auto_psv)) _T2Interrupt(void)

    TMR2 = 0;            // Reset timer for next event
    IFS0bits.T2IF = 0;   // Clear interrupt flag
}

Timer Allocation

The block automatically allocates timers using MCHP_Fun.TimerConfig():

% Timer allocation example (from callback)
[TimerNbr, TimerName] = MCHP_Fun.TimerConfig(...
    blk, ...              % Block handle
    'OC_SW', ...          % Resource type
    Channel, ...          % Channel number
    MCHP ...              % MCHP structure
);

% Returns:
%   TimerNbr: Timer number allocated (2, 3, 4, 5, etc.)
%   TimerName: String identifier ('Timer2', 'Timer3', etc.)

Register Configuration

// Timer setup (example for Timer2)
T2CONbits.TON = 0;         // Stop timer during configuration
T2CONbits.TCS = 0;         // Internal clock (FCY)
T2CONbits.TCKPS = prescaler; // Set prescaler

PR2 = period_value;        // Set period
TMR2 = 0;                  // Clear timer count

IFS0bits.T2IF = 0;         // Clear interrupt flag
IEC0bits.T2IE = 1;         // Enable timer interrupt
T2CONbits.TON = 1;         // Start timer

// GPIO configuration
TRISAbits.TRISA0 = 0;      // Set as output
LATAbits.LATA0 = 0;        // Initialize low

Block Usage Examples

Example 1: Variable Frequency Square Wave

Application: Generate square wave with dynamically adjustable frequency

% Block parameters
Channel: 1
Mode: 32                   % Toggle mode
InputPeriod: 'is a block input'
PIN_OC1: 'RA0'

% Simulink model
[Frequency Command] โ†’ [1/f Calculator] โ†’ [Gain: FCY/2]
                   โ†’ [OC1_Toggle input]

% Example: For 1 kHz output at 60 MHz FCY
% Toggle period = 60,000,000 / (2 ร— 1000) = 30,000 counts
% This creates 1 kHz square wave (toggle every 500 ยตs)

Example 2: Precise Pulse Width Modulation

Application: Servo motor control with microsecond precision

% Block parameters
Channel: 1
Mode: 5                    % Up + Period
InputPeriod: 'is a parameter'
Period: 20000              % 20 ms for servo (50 Hz)
PIN_OC1: 'RB3'

% Simulink model
[Servo Angle -90 to +90] โ†’ [Gain & Offset: 1000-2000 ยตs]
                        โ†’ [OC1_Up input]

% Creates 1-2 ms pulses at 50 Hz for standard servo control
% Pulse width determines servo angle

Example 3: Asymmetric PWM for Power Supplies

Application: Buck converter with independent rise/fall timing

% Block parameters
Channel: 1
Mode: 3                    % Up & Down (independent control)
PIN_OC1: 'RC2'

% Simulink model
[Voltage Controller] โ†’ [Dead-time Compensator]
                    โ†’ [OC1_Up: Rising edge timing]
                    โ†’ [OC1_Down: Falling edge timing]

% Allows precise control of both edges for:
% - Dead-time insertion
% - Resonant switching optimization
% - Frequency modulation

Example 4: Multi-Channel Synchronized Outputs

Application: Three-phase waveform generation

% Block parameters
Channel: [1 2 3]
Mode: [32 32 32]           % Toggle mode for all
InputPeriod: 'is a parameter'
Period: 1000               % Base frequency

% Simulink configuration
% Three separate OC_SW blocks with phase-shifted initialization:
% Block 1: Initial state HIGH, starts at t=0
% Block 2: Initial state HIGH, starts at t=T/3
% Block 3: Initial state HIGH, starts at t=2T/3

% Creates 120ยฐ phase-shifted square waves

Timing Considerations

Interrupt Latency

        Typical latency: 10-50 instruction cycles
        Jitter sources: Other interrupts, CPU priority, cache misses
        Mitigation: Use high interrupt priority, minimize concurrent interrupts

CPU Overhead Estimation

ModeInterrupts per CycleOverhead @ 10 kHzNotes
Toggle (32)2~0.1% @ 60 MHzLowest overhead
Up & Down (3)2~0.1% @ 60 MHzTwo state transitions
Up & Period (5)2-3~0.15% @ 60 MHzPeriod reload overhead

Resolution and Limits

Maximum frequency: Limited by interrupt service time

  • Practical limit: ~100 kHz (with 1:1 prescaler @ 60 MHz)
  • Recommended range: 1 Hz - 50 kHz for stable operation
  • For higher frequencies: Use MCHP_OC_HW or MCHP_PWM instead

Troubleshooting

Common Issues

Output Frequency Incorrect

  • Timer prescaler: Verify automatic prescaler calculation
  • Period calculation: Check FCY (instruction frequency) setting
  • Timer overflow: Period value must fit in 16-bit PR register (0-65535)
  • Mode confusion: Toggle mode frequency = 1/(2 ร— toggle_period)

Timing Jitter or Instability

  • Interrupt conflicts: Check for higher-priority interrupts delaying service
  • CPU load: Reduce background task complexity
  • Timer sharing: Ensure timer not used by multiple peripherals
  • Cache effects: Code located in slow memory (PIC32)

No Output Signal

  • Pin configuration: Verify GPIO pin is available and not used elsewhere
  • Timer allocation: Check MCHP_Fun.TimerConfig() succeeded
  • Interrupt enable: Verify timer interrupt is enabled in IEC register
  • Model execution: Ensure Simulink model is running (External Mode or deployed)

Performance Optimization

Reducing Interrupt Overhead

// Optimize ISR for minimal latency
void __attribute__((__interrupt__, no_auto_psv)) _T2Interrupt(void)
    __attribute__((section(".critical_code")));  // Place in fast RAM

// Use inline assembly for time-critical sections (dsPIC)
void __attribute__((__interrupt__, no_auto_psv)) _T2Interrupt(void)

### Best Practices

- **Use toggle mode (32)** when possible - simplest and fastest
- **Minimize ISR complexity** - only update timer and output pin
- **Pre-calculate values** - avoid math in interrupt handlers
- **Choose appropriate prescaler** - balance resolution vs overflow risk
- **Consider hardware alternatives** - use OC_HW if CPU overhead is concern

## Related Blocks

- [**MCHP_OC_HW**](output_compare_hw) - Hardware output compare (lower CPU overhead)
- [**MCHP_TIMER_Config**](../timers/timer_config) - Timer resource management
- [**MCHP_IC**](input_capture) - Measure external pulse timing
- [**MCHP_PWM**](../pwm_io/pwm) - Dedicated PWM peripheral
- [**MCHP_Digital_Output**](../digital_io/digital_output) - Basic GPIO output control

## See Also

### Application Notes

- [AN1156](https://www.microchip.com/AN1156)
- [AN580](https://www.microchip.com/AN580)