PDA

View Full Version : Strange HSEROUT behaviour



Charles Linquis
- 7th July 2006, 04:30
If I use HSEROUT near the end of a program, and follow it closely with an "END" statement, the output gets truncated. Sometimes it doesn't display at all.

Since the USART only contains two possible bytes - one in the TXReg and one in the send buffer, I would think that at most two bytes would be "chopped off". But instead, sometimes whole lines fail to display. Does anyone know why this happens?

Another HSEROUT issue (possibly related): When I have a timer interrupt running
(a pure assembler routine) and an interrupt occurs, it crashes the HSEROUT string. In the ISR, I save and restore STATUS,W,BSR and FSR. All the other changed variables are local. Is there some software timing loop hidden within the HSEROUT routine, or is something else going on? Are there other registers that I should save and restore?

Christopher4187
- 7th July 2006, 12:48
I experienced something similiar but not sure if it is the same issue as yours. I found that I needed to put a pause statement of 20 milliseconds right after the HSEROUT. I am using this wirelessly and I thought this was the reason. I'm just curious, can you try different pause lengths right after the HSEROUT and let me know what you see?

Chris

Charles Linquis
- 7th July 2006, 13:40
Putting in a PAUSE that is as long as the time it takes to send the string does cure the problem, but my goal is to really understand what PBP is doing.
I have what may be the "worlds largest PBP Program" (My 8722 is nearly full), and now I'm adding SNMP protocol and another layer of interrupts (assembler). I'm noticing some weird behavior, and I'm trying to understand what is going on.

Bruce
- 7th July 2006, 15:46
END places the PIC in a tight loop executing SLEEP continuously.

With HSEROUT, PBP loads the outbound character, then issues a call to the
HSEROUT sub-routine. It doesn't wait for the last character to be sent.

Program execution returns to the next statement right after the call to
HSEROUT, lands on SLEEP, kills the CPU clock, and your last character is
never sent.

Here's how it works;


DEFINE OSC 4

HSEROUT ["AB"]

END
Which produces this in assembler;


0000 GOTO INIT
0001 HSEROUT CLRWDT
0002 BTFSS PIR1, 0x4
0003 GOTO HSEROUT
0004 MOVWF TXREG
0005 BSF STATUS, 0
0006 GOTO DONE
0007 DONE BCF STATUS, 0x7
0008 BCF STATUS, 0x6
0009 BCF STATUS, 0x5
000A CLRWDT
000B DONERET RETURN
000C INIT BSF STATUS, 0x5
000D MOVLW 0x19
000E MOVWF TXREG
000F MOVLW 0x20
0010 MOVWF RCSTA
0011 BCF STATUS, 0x5
0012 MOVLW 0x90
0013 MOVWF RCSTA
0014 MAIN MOVLW 0x41 ; <-- load 1st character
0015 CLRF PCLATH
0016 CALL HSEROUT ; <-- send it
0017 MOVLW 0x42 ; load 2nd character
0018 CLRF PCLATH
0019 CALL HSEROUT ; <-- send 2nd character
001A SLEEP <-- goes to sleep before 2nd character is sent
The PIC is executing instructions a lot faster than your 8-bit serial data can
be shifted out, so it returns and lands on the SLEEP instruction long before
data can be sent.

You need a pause after HSEROUT for a period of at least 1/baud rate*10 or
loop until the TX buffer flag indicates the last char has been sent.

Charles Linquis
- 7th July 2006, 16:52
Thanks, Bruce!
That is exactly the type of explanation that I was looking for.

Going back to my original question, I find that my ISR "kills" HSEROUT.
Is there some reason why this would happen?

As I mentioned, I'm saving and restoring W,STATUS,BSR, and FSR.

Bruce
- 7th July 2006, 17:17
What's causing it to crash could be several things, but it's impossible to tell
without seeing all of your code.

How often are your interrupts? What happens in your interrupt handler?

mister_e
- 7th July 2006, 19:09
what happen if...


Disable
HSEROUT ["Your String"]
WHILE TXREG : WEND
Enable
END


Now how about


HSEROUT ["YourString"]
WHILE TXREG : WEND
end

Charles Linquis
- 7th July 2006, 21:07
This is on a 1 millisecond interrupt. Chip is 18F8722

Here is a portion of the code...


Asm
IntHandler

movwf wsave
swapf STATUS,W
clrf STATUS
movwf ssave
movf PCLATH,W
movwf psave
movf FSR0,W
movwf fsave

movlw 0xEC ; Reload TMR0 with 65535 - 5000
movwf TMR0H
movlw 0x77
movwf TMR0L

btfsc PIR1,5
goto KeyHit

bcf INTCON,2 ; Clear the interrupt flag

infsnz _MasterClock
incf _MasterClock + 1

movlw 0x03
cpfseq _MasterClock + 1
goto FanRoutine
movlw 0xE8
cpfseq _MasterClock
goto FanRoutine
clrf _MasterClock
clrf _MasterClock + 1


bsf _TPE
goto DoneForNow


FanRoutine

movf PORTB,0,0
movwf _Temp,0
xorwf _OldPortB,0,0
movwf _changedB,0
movff _Temp,_OldPortB


Fan1
btfss _changedB,0
goto DoneForNow
infsnz _Fan1Counter
incf _Fan1Counter+1



KeyHit
bsf _KeyHitFlag
bcf PIR1,5

DoneForNow

movf psave,W
movwf PCLATH
movf fsave,W
movwf FSR0
swapf ssave, W
movwf STATUS
swapf wsave, F
swapf wsave, W
bsf INTCON,7 ; Turn Global interrupts on
bsf INTCON,6 ; Turn Peripheral Interrupts on
retfie ; Return from the interrupt

EndAsm

Bruce
- 7th July 2006, 22:46
I suspect it's your int handler.

btfsc PIR1,5
goto KeyHit ; <-- you never reset timer0 int flag before exiting

bcf INTCON,2 ; (skips over this) Clear the interrupt flag

That may be a problem once retfie re-enables global interrupts.

And if you have your USART receive interrupt enabled, you're not clearing the
receive interrupt with BCF PIR1,5. You have to read whatever is in the USART
receive buffer to clear this flag bit.

Have a look at the 18F series interrupt handler in this example;
http://www.microengineeringlabs.com/resources/samples/x1/pbp/serbufAx.bas

Charles Linquis
- 7th July 2006, 23:18
That link sends me to a 16F interrupt handler. Will the same code work on an 18F part?

While I was visiting the MELABS site, I noticed an 18F452 interrupt routine for the timer.

They only saved/restored "W" and "STATUS".
In the 18F series, do I not have to worry about any other registers if I'm not explicity changing them?

Bruce
- 7th July 2006, 23:37
Sorry. Try this one;
http://www.microengineeringlabs.com/resources/samples/18F/serA452.bas

Normally you'll only need to save FSR0L, FSR0H, WREG and STATUS.