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
interrupts.
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
nop
nop
nop
nop
bcf INTSCOPE
btfsc INT_FLAGS, L4DB ;Are we looking for data bits
goto CK4DB
btfsc INT_FLAGS, L4SB ;Are we looking for a start
bit
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
StartBit
bsf INTSCOPE
bcf INTSCOPE
; bcf INTCON, INTE ;turn off falling edge
interrupt
bcf INTCON, INTF ;clear int occured flag
bcf INT_FLAGS, L4SB ;Found the start bit
bsf INT_FLAGS, L4DB ; now start looking for data
bits
bcf RED_LED
bsf YEL_LED
clrf DBCount ;Init Data bits count
movlw d'170'
movwf TMR0 ; delay till middle of
first data bit
nop
bcf INTCON, T0IF ;always do this before
enabling
nop
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
DataBit
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
StopBit
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
nop
bsf INTCON, INTE ;Turn the rb0/int back on for
falling edge detection
btfss INTCON, INTE ;make sure
goto $-2
; Restore everything and return
IntExit
swapf STATUS_TEMP, W
movwf STATUS
swapf W_TEMP, F
swapf W_TEMP, W
retfie
Michael Brown
Instant Net Solutions
http://www.KillerPCs.net
--
http://www.piclist.com 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
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
--
http://www.piclist.com 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(http://www.phanderson.com/PIC/16C84/interrupts/interrupt_1.html) 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
http://www.KillerPCs.net
{Original Message removed}
2001\04\08@085350
by
Alan B. Pearce
>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.
--
http://www.piclist.com hint: The list server can filter out subtopics
(like ads or off topics) for you. See http://www.piclist.com/#topics
More... (looser matching)
- Last day of these posts
- In 2001
, 2002 only
- Today
- New search...