Searching \ for '[PIC]: Lost Interrupts using TMR0 receiving serial' in subject line. ()
Make payments with PayPal - it's fast, free and secure! Help us get a faster server
FAQ page:
Search entire site for: 'Lost Interrupts using TMR0 receiving serial'.

Exact match. Not showing close matches.
PICList Thread
'[PIC]: Lost Interrupts using TMR0 receiving serial'
2001\04\07@121642 by michael brown

I am attempting to use a pic 16f84a to receive serial data at 9600 baud and
display it onto a 4*20 LCD. I use the rb0/int function to detect the falling
clock edge (indicating the beginning of a start bit). When this is detected
I disable the rb0/int and start TMR0 to cause an interrupt during the middle
of the first data bit. When this interrupt occurs I detect the data bit and
store it into serialData. I then restart TMR0 to cause an interrupt during
the middle of the next data bit. I do this until I have received an
interrupt during the stop bit.  During this interrupt I pass the received
byte(InByte) up to the main level code.  I then disable TMR0 and re-enable
the RB0/INT function to detect the next start bit.

The main level code just loops looking for a non-null value in this passed
byte. When one is detected it is displayed on the LCD panel.  This will be
changed to a 32 byte circular queue to hold data until it can be displayed.

This all seems to work great, UNTIL you send serial data to the PIC faster
than some(undetermined) rate. 20 to 30 bytes per second is handled fine.
However if data is sent to fast, the pic seems to get into a state where the
TMR0 is not generating interrupts. I have gone so far as to use external
LED's to display the current status of my state machine logic.  The LED's
are clearly indicating that the state machine is waiting for TMR0
interrupts, but not receiving them.

I fully realize that data (at 9600 baud) can come in much faster than the
LCD can display it.  But, I should just see lost or garbled characters, not
a complete apparent lock-up of the pic.  This definitely seems like some
kind of timing issue, since it will receive thousands of bytes without error
(as long as they are not too close together). Yet it will fail almost
instantly when back to back bytes are received.  I have spent many hours
trying different things like setting the INTCON bits within a loop, testing
to see if it really was set. I have used nops, switched code around etc...
Currently the code does not disable the RB0/INT interrupts, they are just
simply ignored by my state machine implementation.  Since they are not
disabled, I can tell by the oscilloscope that the pic is still alive and
running, responding to the incoming falling clocks, but not getting its TMR0

Below is my interrupt handling routine. Please don't laugh as I am new to
this architecture. Although I have been programming in various assembly
languages for about 15 years. I have been doing this long enough to know
that just when you think the hardware is not working properly, you need to
look harder at your code.  However, I am aware that the pic does contain
timing quirks when it comes to the RMW.  Am I going crazy or what?

I will be eternally grateful to anyone who can help me with this.

#define         SERIAL_IN      PORTB, 0
#define         INTSCOPE       PORTA, 2                ; This pin is
monitored with an Oscilloscope to verify interrupts are occurring
#define         RED_LED         PORTA, 1               ;LED's to indicate
state of the state machine
#define         YEL_LED         PORTA, 0

             org         0x004

             movwf       W_TEMP              ;Save everything
             swapf       STATUS, W
             movwf       STATUS_TEMP
; Interrupt handler right here
             bsf         INTSCOPE            ;Show heartbeat pulse 5us wide
             bcf         INTSCOPE

             btfsc       INT_FLAGS, L4DB     ;Are we looking for data bits
              goto       CK4DB
             btfsc       INT_FLAGS, L4SB     ;Are we looking for a start
              goto       CK4SB
             goto        IntExit             ;Who knows how we got here

CK4DB        btfsc        INTCON, T0IF        ;Is it timer0
                     goto        DataBit
                     bcf          INTCON, INTF        ;Just in case
                     goto        IntExit

CK4SB         btfsc       INTCON, INTF        ;Is it a start bit
                     goto       StartBit            ;Yes
                     bcf          INTCON, T0IF        ;Just in case
                     goto        IntExit

             bsf         INTSCOPE
             bcf         INTSCOPE

;              bcf         INTCON, INTE             ;turn off falling edge
             bcf         INTCON, INTF              ;clear int occured flag
             bcf         INT_FLAGS, L4SB      ;Found the start bit
             bsf         INT_FLAGS, L4DB      ; now start looking for data
             bcf         RED_LED
             bsf         YEL_LED
             clrf        DBCount                      ;Init Data bits count

             movlw       d'170'
             movwf       TMR0                    ; delay till middle of
first data bit
             bcf         INTCON, T0IF          ;always do this before
             bsf         INTCON, T0IE         ;turn on the timer interrupt
             btfss       INTCON, T0IE        ;make sure it is really on
              goto $-2                                ;if not, try it again
             goto        IntExit

             incf        DBCount, F
             movf        DBCount, W
             xorlw       0x09                      ;Do we have 8 bits yet?
             btfsc       STATUS, Z
              goto       StopBit                  ;Stop bit received
; This is Data bit to keep
             bsf         INTSCOPE            ;1 us heartbeat pulse
             bcf         INTSCOPE
             movlw       d'175'                   ;Re-load Timer0 for next
data bit
             movwf       TMR0
             bcf         INTCON, T0IF        ;Clear Int occured flag
             nop                                        ;something to try,
but it doesnt work
             bsf         INTCON, T0IE        ;Re-enable Timer0
             btfss       INTCON, T0IE
              goto $-2
; Read in the bit and pre-pend it to what we have so far
             clrc    ; assume clear carry
             btfsc       SERIAL_IN  ; if receiving 0
              setc    ; set carry
             rrf         serialData, F  ; roll serialData bits directly
into the field
             goto        IntExit

             bsf         INTSCOPE
             bcf         INTSCOPE
             bcf         INTCON, T0IE        ;Turn off timer0
             bcf         INTCON, T0IF

             movf        serialData, W       ;Get the byte received and
             movwf       InByte              ;  pass it to main level loop

             bsf         INT_FLAGS, L4SB     ;Looking for a start bit now
             bcf         INT_FLAGS, L4DB     ; not data bits
             bsf         RED_LED
             bcf         YEL_LED
             bcf         INTCON, INTF        ;clear interrupt occured flag
             bsf         INTCON, INTE        ;Turn the rb0/int back on for
falling edge detection
             btfss       INTCON, INTE        ;make sure
              goto $-2
; Restore everything and return
             swapf       STATUS_TEMP, W
             movwf       STATUS
             swapf       W_TEMP, F
             swapf       W_TEMP, W

Michael Brown
Instant Net Solutions

-- hint: PICList Posts must start with ONE topic:
[PIC]:,[SX]:,[AVR]: ->uP ONLY! [EE]:,[OT]: ->Other [BUY]:,[AD]: ->Ads

2001\04\07@205840 by Jinx

face picon face
These definitely need NOPs between the bsf/bcf

> StartBit
>               bsf         INTSCOPE
>               bcf         INTSCOPE

> ; This is Data bit to keep
>               bsf         INTSCOPE            ;1 us heartbeat pulse
>               bcf         INTSCOPE

> StopBit
>               bsf         INTSCOPE
>               bcf         INTSCOPE

You say you're picking up data OK at 20-30 bytes/sec but not
faster than this. The only difference then would seem to be the
length of the idle period between Stop/Start bits. Doesn't
explain why TMR IRQs are missing. Maybe at a slower speed
somehow the port has a chance to "recover" from a r-w-m
problem but can't cope with a fast procession of them. Get
those NOPs in and see what happens

-- hint: PICList Posts must start with ONE topic:
[PIC]:,[SX]:,[AVR]: ->uP ONLY! [EE]:,[OT]: ->Other [BUY]:,[AD]: ->Ads

2001\04\07@215422 by michael brown

Thank you for your reply. I really need all the help I can get.  It turned
out that I definitely was losing my mind.  I was switching to bank 1(to flip
portb between input and output to do scrolling on the LCD and to check the
busy flag on the LCD) in the main level code, but leaving interrupts turned
on. Sure enough, with a short enough pause between bytes, I would end up in
the interrupt routine while switched to bank 1.  I couldn't think of better
way to work around this than to load FSR with the address of TRISB (since
this was the only field I needed in bank 1) then I just used INDF to access
the TRISB leaving the main level code running in bank 0 only, and not ever
switching.  I saw a web
page( where
he was saying that you could just switch to bank 0 in the interrupt routine
and not worry about the bank that was being used. Since the bank pointer
would be re-established when you restored the STATUS register before
executing the RETFIE.  This doesn't seem right to me since in his example he
is blindly saving the W reg and the STATUS regs into whichever bank was
currently selected then restoring them from bank 0 before exiting.  This
would seem to lead to unpredictable behavior. :-o

But thank you very much anyway.  Wouldn't you know I would struggle for days
on this and then finally ask for help right before figuring it out.  It
seems to work fine now, only I lose characters at high speeds.  That's OK
though, now to implement that circular queue.

Michael Brown
Instant Net Solutions

{Original Message removed}

2001\04\08@085350 by Alan B. Pearce

face picon face
>This doesn't seem right to me since in his example he
>is blindly saving the W reg and the STATUS regs into whichever bank was
>currently selected then restoring them from bank 0 before exiting.  This
>would seem to lead to unpredictable behavior. :-o

Only if the registers where W and Status are saved is not in both banks.
Check the documentation for the chip you are using as some RAM locations can
be accessed from any bank, and are ideal for this use.

-- hint: The list server can filter out subtopics
(like ads or off topics) for you. See

More... (looser matching)
- Last day of these posts
- In 2001 , 2002 only
- Today
- New search...