I guess I'm not seeing how the debugging pins are being used (D3/D4), as I only see them being set in that code so am not sure where/how they are cleared.
Anyway, from my limited abilities it seems your problem boils down to why is the OC0B pin not set right away in one case, and in the other it appears the OC0B pin is set right away.
From the datasheet-
The PWM waveform is generated by setting (or clearing) the OC0x Register at the compare
match between OCR0x and TCNT0, and clearing (or setting) the OC0x Register at the timer clock cycle
the counter is cleared (changes from TOP to BOTTOM).
I'm not sure if that means the SET on OC0B (pwm non-inverting) will NOT occur when the timer is manually set to 0, then enabled? (since there is no 'changes from TOP to BOTTOM' when you enable the pwm again. That would explain the 'missing' pulse, but then it would seem that should happen every time.
additional info, and I think it makes sense if the datasheet says what I think it says-
carrier_cycles = 2
oc0b = 1 (PWM SET)
ocr0b match
oc0b = 0 (PWM CLEAR)
timer TOP->BOTTOM
oc0b = 1 (PWM SET)
timer overflow irq
carrier_cycles = 1
irq exit
ocr0b match
oc0b = 0 (PWM CLEAR)
timer TOP->BOTTOM
oc0b = 1 (PWM SET)
timer overflow irq
carrier_cycles = 0
clear ocf0b
wait for ocf0b
oc0b = 0 (PWM CLEAR)
stop timer, disable output
exit irq
waiting to start timer again
oc0b = 0 (PWM CLEAR) still clear
set timer to 0, start timer
NO TOP->BOTTOM, so NO oc0b SET
HERE IS THE 'MISSING' PULSE
same but WITHOUT delay in irq, the oc0b output remains SET when the timer is stopped- when timer starts again oc0b output is still SET
I'm quite confused at this point, but I think the above is correct, or should help I think.
summary- with delay, oc0b pwm remains CLEAR and starting the timer at 0 produces no SET
without delay, timer is stopped while oc0b is SET, so when timer started at 0, the setting of the com bit re-enables the last state of 0c0b which was SET
Here is an alternate idea (only because I recently created an LG 2 button remote using a pic10lf322)-
I simply leave the pwm enabled, and change the duty to 0 or 25% as needed. The timer overflow is manually counted (I have nothing better to do, so do not need irq). Since the compare is double buffered, I just set the pwm back to 0% at the end of every bit and the next bit will override it long before the buffered reload occurs. The advantage is I never have to worry about that last pwm. One other tip I discovered by accident- leave off that last end pulse to 'invalidate' the previous frame (I was using long button presses for other functions but for faster response I wanted to get the frame going in case it was a short press- before the last end pulse, I check the button again, if button still pressed I don't send the end pulse, but instead wait for the frame time to expire and send a new code.
#define IR_T1 21 //first half of every bit, seond half of bit0
#define IR_T2 63 //second half of bit1
#define IR_TS1 339 //start- on
#define IR_TS2 170 //start- off
#define IR_TIDLE 1492 //idle time
#define IR_TIDLER 3630 //idle time after repeat
#define IR_TFRAME 4077 //total frame time (108ms)
void ir_pulse(uint16_t c, bool b)
{
if(b){ //on
//25% duty (will be loaded at next overflow)
pwm_duty(1);
}
for( ; c; c--, TMR2IF = 0 ) while( !TMR2IF );
//0% duty - output off (will be loaded at next overflow)
//any other value loaded before tmr2if will override it
pwm_duty(0);
}
//******************************************************************************
// nec ir frame
// start pulse, address, naddress, data, ndata, end pulse, idle
// nec start pulse - 9ms on, 4.5ms off
// nec bit 0 pulse - 562.5us on 562.5us off - total 1.125ms
// nec bit 1 pulse - 562.5us on 1.675ms off - total 2.225ms
//******************************************************************************
void ir_frame_nec(uint8_t a, uint8_t d)
{
union { uint8_t dat4[4]; uint32_t dat32; } u;
u.dat4[0] = a; u.dat4[1] = ~a; u.dat4[2] = d; u.dat4[3] = ~d;
pwm_init( IR_NEC_PR2 );
ir_pulse( IR_TS1, 1 ); //start 9ms on
ir_pulse( IR_TS2, 0 ); //4.5ms off
for( uint8_t i = 32; i; i--, u.dat32 >>= 1 ){ //data
ir_pulse( IR_T1, 1 ); //on time always same
ir_pulse( u.dat32 & 1 ? IR_T2 : IR_T1, 0 ); //off time
}
ir_pulse( IR_T1, 1 ); //end pulse
ir_pulse( IR_TIDLE, 0 ); //idle
}