• AVR Freaks

Hot!Using output compare as interrupt timebase?

Author
AndersG
Super Member
  • Total Posts : 207
  • Reward points : 0
  • Joined: 2008/08/05 04:51:24
  • Location: 0
  • Status: offline
2020/04/14 07:25:35 (permalink)
0

Using output compare as interrupt timebase?

I just have to ask as i cannot seem to wrap my head around this :) I need to create a bitbanged, interrupted UART that can do 15 bit data. I thought I'd set up two timebases, one for transmit and one for receive. On transmit of an integer I shove it into the TCX buffer zero the OC counter and start the OC timer and then just clock out each bit, one per interrupt and when done I turn off the OC timer. For reception I have one interrupt that catches the start bit and starts the timer, initially with 1.5 bit time then 1 bit time and clock in the data. PIC 24FJ64GB00464MHz
 
Transmit:
//
// Output compare 1 interrupt. Transmit timer
// Shift out the bits in TXRegister and turn off timer interrupt when done.
//
void __attribute__((__interrupt__, auto_psv)) _OC1Interrupt( void )
{
    LATBbits.LATB5 = TXRegister & 1;
    //__delay_us(1);
    TXRegister = TXRegister >> 1;
    TXCounter--;
    if(TXCounter == 0)
    {
        LATBbits.LATB5 = 1;
        IEC0bits.OC1IE = 0; // All done?
    }
    IFS0bits.OC1IF = 0; // clear the interrupt bit
}

 
Problem I have is that I do not quite understand the OC initialisation, even if it works. I just need an OC interrupt, nothing else and this is what I have:
    // Testing 115200 baud. Bit time 8,68us
    // Timer clock Fosc/2 = 32MHz, 278 ticks
    //
    OC1CON1 = 0;
    OC1CON2 = 0;
    OC1CON1bits.OCTSEL = 7; // System clock
    OC1CON1bits.OCM = 0b011;
    //
    OC1CON2bits.SYNCSEL = 0b11111;
    OC1CON2bits.OCTRIS = 1;
    //
    OC1RS = 138;
    OC1R = 0;

I thought I'd have to put the timer value in OC1R, but not so. It goes into OC1RS and the value is not what I have calculated, so I must be doing something wrong. Can anyone enlighten me?
#1

6 Replies Related Threads

    Beau Schwabe
    Starting Member
    • Total Posts : 29
    • Reward points : 0
    • Joined: 2019/09/23 21:16:53
    • Location: 0
    • Status: offline
    Re: Using output compare as interrupt timebase? 2020/04/14 09:07:35 (permalink)
    0
    I was going to say why bit bang the UART while that particular IC has two of them built in.... and then I saw that you needed 15 bits.
     
    I have bit banged plenty of UART's and what I have always settled on as far as with interrupts ... Let the interrupt handle the receive only and just use a standard subroutine to send.  When you bit bang a received byte or (word) in your case make sure you check for any framing errors.  IOW look at the STOP bit before you validate the data.  Once the data is validated, FIFO the byte (word) into your data receive buffer.  If you are sending packets (variable or fixed) check for a valid packet via a BYTE count in combination with a timeout delay between BYTES and a CRC of some kind ( a simple XOR CRC is usually sufficient) .  If all of that checks out, then validate the packet.  Once you have a valid packet, then it can be processed in normal running code.  Typically I look at the packet header for it's existence, if it is there then I process the packet through a simple decision tree and clear the packet header after processing.
     
    Note: Inside the interrupt make sure you pay attention to context saving when entering and leaving the interrupt.
     
    As far as capturing an input event, you might be better off using the "Input Capture" with the pre-scaler set to 1:1 and configuring the ICM<2:0>  and IC1<1:0> appropriately.
     
    You might also be able to get tricky using the SPI interface in slave mode and providing a clock pulse to SCKx representing the baud rate.
    post edited by Beau Schwabe - 2020/04/14 09:38:54
    #2
    AndersG
    Super Member
    • Total Posts : 207
    • Reward points : 0
    • Joined: 2008/08/05 04:51:24
    • Location: 0
    • Status: offline
    Re: Using output compare as interrupt timebase? 2020/04/15 05:38:25 (permalink)
    0
    Well, that was not entirely what I was asking, but now that I have reread the docs, I realise that interrupts happen when OCxRS matches so that explains it somewhat.
     
    I breifly looked at using the SPI module, at least for transmit, but there I bump into issues with the selected bitrate. The thing that I am interfacing to has a bitrate of 100kHz and I cannot get that from a 32MHz peripheral clock.
    #3
    MBedder
    Circuit breaker
    • Total Posts : 6919
    • Reward points : 0
    • Joined: 2008/05/30 11:24:01
    • Location: Zelenograd, Russia
    • Status: offline
    Re: Using output compare as interrupt timebase? 2020/04/15 08:05:10 (permalink)
    0
    Which exactly is your "thing that I am interfacing to"?
    #4
    AndersG
    Super Member
    • Total Posts : 207
    • Reward points : 0
    • Joined: 2008/08/05 04:51:24
    • Location: 0
    • Status: offline
    Re: Using output compare as interrupt timebase? 2020/04/15 08:38:43 (permalink)
    5 (1)
    "Which exactly is your "thing that I am interfacing to"?"
     
    A HP 9000 300 series computer from the 1980's. They use a protocol called HP HIL, not to be confused with HP-IL, for keyboard and mice. It is a serial protocol, 100k with 15 bits including start and stop bits. The bit stream is made up of addressing and an 8 bit payload.
     
    I think I have it somewhat sorted now. Will post the code later
    post edited by AndersG - 2020/04/15 09:35:58
    #5
    MBedder
    Circuit breaker
    • Total Posts : 6919
    • Reward points : 0
    • Joined: 2008/05/30 11:24:01
    • Location: Zelenograd, Russia
    • Status: offline
    Re: Using output compare as interrupt timebase? 2020/04/15 09:04:28 (permalink)
    0
    OMG LoL
    #6
    AndersG
    Super Member
    • Total Posts : 207
    • Reward points : 0
    • Joined: 2008/08/05 04:51:24
    • Location: 0
    • Status: offline
    Re: Using output compare as interrupt timebase? 2020/05/26 05:35:15 (permalink)
    5 (1)
    Anyway, this is what I did and it works just fine:
    Receive: Use INT0 to start the receive sequence and then OC2 to clock in bits. RB7 input
    Transmit: Use OC1 to clock out bits. RB5 output
     
    //
    // Interrupt routines
    //
    //
    // Data interrupt. Start bit. Turn off this interrupt and start bit-
    // counter.
    //
    void __attribute__((__interrupt__, auto_psv)) _INT0Interrupt( void )
    {
    // LATBbits.LATB8 = 0;
    // LATBbits.LATB8 = 1;
    // LATBbits.LATB8 = 0;
        RXCounter = 16;
        RXRegister = 0;
        OC2TMR = 0; // Start OC2 counter in known state
        OC2CON1bits.OCM = 0b011;
        IEC0bits.OC2IE = 1; // enable OC2 interrupt
        _INT0IE = 0; // disable INT0 interrupt
        _INT0IF = 0; // clear the interrupt bit
    }
    //
    //
    // Output compare 1 interrupt. Transmit timer
    // Shift out the bits in TXRegister and turn off timer interrupt when done.
    //
    void __attribute__((__interrupt__, auto_psv)) _OC1Interrupt( void )
    {

        if(TXCounter <= 0) // All done? We arrive here one last time
        {
            LATBbits.LATB5 = 1;
            IEC0bits.OC1IE = 0;
        }
        else LATBbits.LATB5 = TXRegister & 1;
        TXRegister = TXRegister >> 1;
        TXCounter--;

        IFS0bits.OC1IF = 0; // clear the interrupt bit
    }
    //
    // Output compare 2 interrupt. Receive timer. Count in bits
    // and put in fifo when all received
    //
    void __attribute__((__interrupt__, auto_psv)) _OC2Interrupt( void )
    {
        int i;
       
        if(PORTBbits.RB7) RXRegister = RXRegister | 0b1000000000000000;
        //
        RXCounter--;
        if(RXCounter == 0) // All done?
        {
            IEC0bits.OC2IE = 0;
            OC2CON1bits.OCM = 0;
            i = RxFifo.ct; // Number of bytes in the FIFO
            if (i < BUFFER_SIZE) { // Skip if FIFO is full
                RxFifo.ct = ++i;
                i = RxFifo.wi;
                RxFifo.buff[i] = RXRegister; // Store received data into the FIFO
            }
            _INT0IE = 1; //enable INT0 interrupt for next rx
        }
        else RXRegister = RXRegister >> 1;
        IFS0bits.OC2IF = 0; // clear the interrupt bit
        _INT0IF = 0; //clear the interrupt bit
    }

     
    #7
    Jump to:
    © 2020 APG vNext Commercial Version 4.5