1
\$\begingroup\$

My ATtiny85 circuit generates signals like this one on PB1 (OC0B) using fast PWM (preamble, 16 bit data, stop pulse):

valid signal example screenshot

I have trouble with the leftmost longer pulse. At the moment i use simple _delay_us statements to generate it, but it sometimes introduces glitches later near the end of the PWM (orange and yellow) parts.

It seemed smart to switch to using timers for this part but I can't get it to work correctly. This is my code:

const uint8_t JVC_MUTE = 0x71;
const uint8_t JVC_ADDRESS = 0xF1;

void setupPWM () {
//enables fast pwm, non inverting,TOP=OCR0A, prescaler 8
TCCR0A = (1<<WGM01)| (1<<WGM00)|(1<<COM0B1);
TCCR0B = (1<<WGM02)|( 1<<CS01);
}

void stopPWM () {
TCCR0A = 0;
}

/*emits a long preamble pulse
*/
void preamble(){
//enables fast pwm, non inverting, prescaler 64
TCCR0A = (1<<WGM01)| (1<<WGM00)|(1<<COM0B1);
TCCR0B = (1<<WGM02)|( 1<<CS01)|(1<<CS00);
TCNT0=0;
OCR0A=255;
OCR0B=80;
do ; while ((TIFR & 1<<OCF0B) == 0);
TIFR = 1<<OCF0B;
TCCR0A = 0;
}

/*emits 16 bit of data using fast PWM
code:16 bit data value to be send (address + command)
*/
void sendCode (uint16_t code) {
TCNT0=0;

    //padding instructions 1
OCR0A=0;
OCR0B=0;
do ; while ((TIFR & 1<<OCF0B) == 0);
TIFR = 1<<OCF0B;
    //padding instructions 2
OCR0A=0;
OCR0B=0;
    //waits while polling the OCF0B bit signaling a compare match with OCR0B
do ; while ((TIFR & 1<<OCF0B) == 0);
TIFR = 1<<OCF0B;

            //loops through each bit in the 'code' variable
            //and emits a long or short pulse depending on value
    for (uint16_t Bit=0x8000;Bit;Bit=Bit>>1){
            //if 1
        if (code & Bit) {
        OCR0A=255;
        OCR0B=80;
    }
            //if 0
    else {
        OCR0A=130;
        OCR0B=80;
    };
    do ; while ((TIFR & 1<<OCF0B) == 0);
    TIFR = 1<<OCF0B;
}
//emits a short pulse signaling the end of the transmission
OCR0A=130;
OCR0B=80;
do ; while ((TIFR & 1<<OCF0B) == 0);
TIFR = 1<<OCF0B;

}

/*
*emits a transmission (preamble pulse, 16 bit of data + end pulse)
*/
void transmit(uint8_t address,uint8_t code){
preamble();
setupPWM();//PWM settings in TCCR0A and TCCR0B
sendCode((JVC_ADDRESS<<8)+JVC_MUTE);
stopPWM();//disables PWM (TCCR0A=0)
}

There are two issues:

  1. This code will generate the preamble pulse the first time, followed by glitched data, and then only the glitchy data when called
    consecutively.
  2. It needs the padding instructions I added in sendCode(), otherwise the 2 first bits of the transmission are always cut.

edit: the actual data part (orange and yellow parts), as well as the stop pulse at the end work fine when the call to preamble() is commented out. The only issue is with the preamble() part.

I'd appreciate any help, especially with point 1.

\$\endgroup\$
4
  • \$\begingroup\$ If I am reading the code correctly it seems like your bit shift operators << are being used unusually. Also verify that when you use the single & operator in your 'while' loops that you do in fact want the bitwise AND that you have there rather than a logical AND &&. \$\endgroup\$ Commented Oct 6, 2017 at 16:29
  • \$\begingroup\$ This part as I understand it creates a 16 bit value of 0x8000, then gradually shifts the 1 right to test each bit of the 'code' variable. It works reliably when the call to preamble() is commented out. \$\endgroup\$
    – Polyphil
    Commented Oct 7, 2017 at 9:26
  • \$\begingroup\$ preamble() and setupPWM() select different prescaler clock sources. One sets only CS1, while the other sets CS1 and CS0. What may be important about that is that the prescaler is essentially a counter which may have a partial count value left over from the other function's use. In both preamble() and also in sendCode() you could try clearing the prescaler before the TCNT0=0; statement by inserting GTCCR=GTCCR|1; then re-enabling it after the TCNT=0; statement by adding GTCCR=GTCCR&0x7f; \$\endgroup\$ Commented Oct 7, 2017 at 20:33
  • \$\begingroup\$ CORRECTION: The second statement should not be GTCCR=GTCCR&0x7f; it should be GTCCR=GTCCR&0xfe; \$\endgroup\$ Commented Oct 7, 2017 at 21:04

1 Answer 1

0
\$\begingroup\$

Clear the count in the prescaler each time you change the prescaler setting. For prescaler 0 the reset bit is the low bit bit of GTCCR. Set, then clear the prescaler reset bit with :

GTCCR=GTCCR | 1; GTCCR=GTCCR & 0xfe;

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.