Oshonsoft programs with INTERRUPTS and PARSE

Thread Starter

camerart

Joined Feb 25, 2013
3,830
I tested PICBASIC v.7.85 ( pic12f683 ) and found no faults in Leftstr, Rightstr.
Can you give examples of the faults.
Hi J,
I can't, because it is intermittent, in other words, a program that works one day, doesn't the next. This happened previously, then it went away for months.
In the programs I have been using there was 2x of the LEFTSTR and RIGHTSTR plus MIDSTR in the program, then suddenly only the MIDSTR have results.
Having changed to all using MIDSTR, I'm getting all results again.

I just tried an old program and today it's working ok.
C
 

Thread Starter

camerart

Joined Feb 25, 2013
3,830
Hi,
I've modified #159 and now it may be ok. Perhaps I'll try a RING BUFFER before adding it into the FULL program.
C
 

Thread Starter

camerart

Joined Feb 25, 2013
3,830
Hi,
In my #159 CODE, I have [ If PIR1.RCIF = 1 Then char = RCREG ] but no HSERIN.
As mentioned the program works in SIM, but not LIVE, should HSERIN be used? If so, then where is it added?
C
 

jjw

Joined Dec 24, 2013
823
Why do you think Hserin is needed?
char= RCREG should work.
I think Hserin waits until there is character to read?

Hserget reads one character, if it is in Usart buffer., zero otherwise
Hserget char.
 

sagor

Joined Mar 10, 2019
1,049
Hserin does no more than what you are doing with char = RCREG. If you look at the ASM code generated by Oshonsoft, you will see that all he does is wait for the PIR1.RCIF flag to be set, then read the RCREG:

Code:
; 68: Hserin i1
    CALL L0002
    MOVWF 0x03F
; 69:
; 70: End
L0011:    GOTO L0011
; Library code
L0001:
    RETURN
L0002:
L0004:
    BTFSC PIR1,RCIF
    GOTO L0005
    GOTO L0004
L0005:
    MOVF RCREG,w
    RETURN
 

Thread Starter

camerart

Joined Feb 25, 2013
3,830
Why do you think Hserin is needed?
char= RCREG should work.
I think Hserin waits until there is character to read?

Hserget reads one character, if it is in Usart buffer., zero otherwise
Hserget char.
Hi J and S,
Ok, thanks.

I've added the INTERRUPT/PARSE into the full program, which didn't work at first, then I tried HSERIN and it started working, then stopped.
something else is stopping it. These tests need all of the Peripherals, for a proper result, and with them all attached, I can see what's happening at the RX PIN. I'll keep testing, and searching. It's almost working : )
Cheers, C.
 

Thread Starter

camerart

Joined Feb 25, 2013
3,830
Hi,
There apears to be something wrong in the [ char = RCREG ] area!
In previous programs where there was a larger INTERRUPT routine there are a couple of lines:
===============================================================
If PIR1.RCIF = 1 Then
nxt_rxin:
If PIR1.RCIF = 0 Then Goto nxt_rxin
Hserin char
If char = "?" Or char = 0x0a Then Goto msg_eol
If char = "$" Then
str1(0) = "$" 'CHAR = $
rxi = 0
Endif
If str1(0) = "$" Then
str1(rxi) = char
rxi = rxi + 1
Goto nxt_rxin
If rxi > 79 Then
Hserout " OVER STR1 LIMIT", CrLf 'Over STR1() limit
rxi = 0
Endif
Endif
Goto nxt_rxin
Endif
======================================================================
In my latest program, I've added similar:
But it stalls the program.
=====================================================================

If PIR1.RCIF = 1 Then char = RCREG
RCIF1:
If PIR1.RCIF = 0 Then Goto RCIF1

buf(rxpsn) = char

If char = "$" Then
rxpsn = 0
buf_fill = 1
Endif

If buf_fill = 1 Then
If char = "W" Then
buf_done = 1
RCSTA.CREN = 0 'INTERRUPT DISABLED
buf_fill = 0
Else
If buf_done = 0 Then
rxpsn = rxpsn + 1
Endif
Endif
Endif

If rxpsn > rxsize Then rxpsn = 0
=============================================================
I can see that it is nested differently, but how can I do it correctly?
C.
 

jjw

Joined Dec 24, 2013
823
It stalls because Hserin waits a char to be received.
Same for:
RCIF1:
If PIR1.RCIF = 0 Then Goto RCIF1

ISR should not wait, but return when a character has been received.
 

Thread Starter

camerart

Joined Feb 25, 2013
3,830
It stalls because Hserin waits a char to be received.
Same for:
RCIF1:
If PIR1.RCIF = 0 Then Goto RCIF1

ISR should not wait, but return when a character has been received.
Hi J,
The first instance in #167 between =========== and =========== didn't stall, but the second one does!

Are you suggesting that [RCIF1: If PIR1.RCIF = 0 Then Goto RCIF1] shoudn't be included?

I have just added it into my program, because I can 'see' the Data arriving at the RX PIN, but it isn't being READ? This appears to be either intermittent or my bad programming?
C
 

sagor

Joined Mar 10, 2019
1,049
#1: Never, never put an Hserout string in an interrupt routine. It takes too long and you will miss incoming characters because you cannot trigger the RX interrupt again. For every character in an Hserout, you may receive another RX character. A Hserout in your interrupt routine of more than 2 characters will likely cause an OERR error because you are NOT processing RCREG while Hserout is running.
#2: Sloppy code. Check which Interrupt flag it is, process the one character then check any/all other interrupt flags and then get out. Before exiting Interrupt routine, do that one last check if any more characters in RXREG. Do something like this as interrupt routine: (just a suggestion of course, there may be better ways of doing this)

Code:
'Start interrupt routine. Check for errors first here
Save System
RXstart:
'... Your error checking code here
'If errors, clear them and exit rpoutine
'Now process what triggered interrupt if no errors

If PIR1.RCIF = 1 then
...
... your RX character coding
...
Endif   'End of single RX character processing

'Now that we have processed one character, check if more...
'Remember that RCIF gets cleared by system when RXREG is empty
if PIR1.RCIF = 1 then goto RXstart  'This makes it a tight loop to read RCREG until empty

'If here, means that RCREG is empty...
'Jump to interrupt exit or proceed to next interrupt flag check (like timer flags, I/O change interrupt, etc.)
...
... More interrupt processing for different interrupts, if required
...
'End of all interrupt processing
IntEXIT:
'before we exit, re-check once more if any more characters in RX buffer'
'No harm in checking several times, at end of each interrupt flag check (like timer flags, IO pin change, etc.)
if PIR1.RCIF = 1 then goto RXstart    'Have a new character in RCREG
Resume
 

sagor

Joined Mar 10, 2019
1,049
In your code:
If PIR1.RCIF = 1 Then char = RCREG
RCIF1:
If PIR1.RCIF = 0 Then Goto RCIF1
buf(rxpsn) = char
if you have only one character, RCIF gets cleared in the first line when you do char = RCREG. Your loop then waits "forever" until another character is received before continuing. If this happens on the last character of your string, you may wait a long time. Never put an indefinite loop in an interrupt routine. Interrupts are there to "notify" you when something happens, don't sit in the interrupt routine "waiting" for it.

The line: RCSTA.CREN = 0 'INTERRUPT DISABLED
does NOT disable interrupts, it just disables the UART receiver. If there is a character (or two) already waiting in RCREG, they will still be there, waiting to be read, and can still trigger interrupts because PIR1.RCIF will stil be set. However, if PIR1.RCIF = 0, then it is safe to turn off the UART receiver, but you should also turn off the RX interrupt.
 

Thread Starter

camerart

Joined Feb 25, 2013
3,830
#1: Never, never put an Hserout string in an interrupt routine. It takes too long and you will miss incoming characters..................................................
Hi S,
The top section of #167 (with HSERIN) is an example of INTERRUPT in older programs, that used to work, but I was advised to re-write the INTERRUPT routine, as it was too long.
The bottom section of #167 is my rewrite, and as advised has no HSERIN. This doesn't work, as the DATA at the RX PIN isn't being READ.
C.
 

Thread Starter

camerart

Joined Feb 25, 2013
3,830
In your code:

if you have only one character, RCIF gets cleared in the first line when you do char = RCREG. Your loop then waits "forever" until another character is received before continuing. If this happens on the last character of your string, you may wait a long time. Never put an indefinite loop in an interrupt routine. Interrupts are there to "notify" you when something happens, don't sit in the interrupt routine "waiting" for it.

The line: RCSTA.CREN = 0 'INTERRUPT DISABLED
does NOT disable interrupts, it just disables the UART receiver. If there is a character (or two) already waiting in RCREG, they will still be there, waiting to be read, and can still trigger interrupts because PIR1.RCIF will stil be set. However, if PIR1.RCIF = 0, then it is safe to turn off the UART receiver, but you should also turn off the RX interrupt.
Hi again S,
I'm looking for the RX INTERRUPT. I tried a couple of guesses, but I think they were wrong!
C.
 

sagor

Joined Mar 10, 2019
1,049
You don't "look" for a RX interrupt, your interrupt routine gets triggered when there is one.
If this is part of your main program (and not part of interrupt routine), you don't just sit there looping, waiting, do something else. All your main program should do is check if the RX buffer has a complete VALID string or not, then process it.
Let the interrupt routine do what it is supposed to do, and have it set flags or indicators for the main program as to what to do next... Your interrupt routine can determine if a string is complete and/or correct before flagging it as "complete".
 

Thread Starter

camerart

Joined Feb 25, 2013
3,830
You don't "look" for a RX interrupt, your interrupt routine gets triggered when there is one.
If this is part of your main program (and not part of interrupt routine), you don't just sit there looping, waiting, do something else. All your main program should do is check if the RX buffer has a complete VALID string or not, then process it.
Let the interrupt routine do what it is supposed to do, and have it set flags or indicators for the main program as to what to do next... Your interrupt routine can determine if a string is complete and/or correct before flagging it as "complete".
Hi S,
In #171 you said "if PIR1.RCIF = 0, then it is safe to turn off the UART receiver, but you should also turn off the RX interrupt. " When I said "I'm looking for the RX INTERRUPT" I meant looking in the DATA sheet. I haven't found it yet!

Here is my INTERRUPT (only) CODE, is it ok? All PARSING etc is done in MAIN LOOP
=============================================================
If RCSTA.OERR = 1 Then 'BIT1..if over run error then flush RXD buffer
If RCSTA.FERR = 1 Then 'BIT2..framing error(can be cleared by reading RCREG register And receiving Next valid Byte)
RCSTA.CREN = 0
RCSTA.CREN = 1 'ENABLES RECEIVER
char = RCREG '1'char = RCREG '1
char = RCREG '2char = RCREG '2
PIR1.RCIF = 0 '0 = The EUSART receive buffer is empty
err = 1 'ERROR
Endif
Endif

If PIR1.RCIF = 1 Then char = RCREG
buf(rxpsn) = char

If char = "$" Then (Start digit of DATA STRING)
rxpsn = 0 (sets first digit in the BUFFER to 0)
buf_fill = 1 (Flag to keep READing DATA)
Endif

If buf_fill = 1 Then
If char = "W" Then (Checks for the END digit of the SERIAL STRING)
buf_done = 1 (Switches off READ DATA flag)
If PIR1.RCIF = 0 Then
RCSTA.CREN = 0 'INTERRUPT DISABLED
(Need to add DISABLE TX INTERRUPT here)
buf_fill = 0 (Sets flag to stop filling BUFFER)
Else
If buf_done = 0 Then ( Sets flag to stop READing and adding)
rxpsn = rxpsn + 1 (INCREMENTs BUFFER address)
Endif
Endif
Endif

If rxpsn > rxsize Then rxpsn = 0

Resume
===========================================================
As the INTERRUPT should now be OFF there should be no digits queuing at the RX PIN. Do I need to check with PIR1.RCIF?
C.
 

sagor

Joined Mar 10, 2019
1,049
In your code:
Code:
If RCSTA.OERR = 1 Then 'BIT1..if over run error then flush RXD buffer
If RCSTA.FERR = 1 Then 'BIT2..framing error(can be cleared by reading RCREG register And receiving Next valid Byte)
RCSTA.CREN = 0
RCSTA.CREN = 1 'ENABLES RECEIVER
char = RCREG '1'char = RCREG '1
char = RCREG '2char = RCREG '2
PIR1.RCIF = 0 '0 = The EUSART receive buffer is empty
err = 1 'ERROR
Endif
Endif

If PIR1.RCIF = 1 Then char = RCREG
buf(rxpsn) = char
.
.
.
What happens when you get an OERR and FERR - you clear it and drop past your ENDIFs and into the code where you set buf(rxpsn) = char. There is NO valid character at that point because PIR1.RCIF=0. You are storing whatever the last "char" was...
Also, if OERR=0 but FERR =1 (or the other way around), you do NOT execute that clearing code because you have nested IF statements. Without both conditions being true, you do not process the error code. You can do an "OR" in the IF statement, like:
Code:
If RCSTA.OERR = 1 OR RCSTA.FERR = 1 THEN
.
.
.
Oshonsoft usually allows one OR statement in an IF statement. (or one AND statement)
Finally, you cannot write to PIR1.RCIF, it is a read-only register. It is cleared when the RCREG is empty

When you detect an error, you clear it and exit....
If PIR1.RCIF = 1 you do a THEN and put the block of code below it and end it with an ENDIF. The way you have it written, the
"If PIR1.RCIF = 1 Then char = RCREG" only does only one thing, and the rest of the code is executed regardless.
 
Last edited:

Thread Starter

camerart

Joined Feb 25, 2013
3,830
In your code:
Code:
If RCSTA.OERR = 1 Then 'BIT1..if over run error then flush RXD buffer
If RCSTA.FERR = 1 Then 'BIT2..framing error(can be cleared by reading RCREG register And receiving Next valid Byte)
RCSTA.CREN = 0
RCSTA.CREN = 1 'ENABLES RECEIVER
char = RCREG '1'char = RCREG '1
char = RCREG '2char = RCREG '2
PIR1.RCIF = 0 '0 = The EUSART receive buffer is empty
err = 1 'ERROR
Endif
Endif

If PIR1.RCIF = 1 Then char = RCREG
buf(rxpsn) = char
.
.
.
What happens when you get an OERR and FERR - you clear it and drop past your ENDIFs and into the code where you set buf(rxpsn) = char. There is NO valid character at that point because PIR1.RCIF=0. You are storing whatever the last "char" was...
Also, if OERR=0 but FERR =1 (or the other way around), you do NOT execute that clearing code because you have nested IF statements. Without both conditions being true, you do not process the error code. You can do an "OR" in the IF statement, like:
Code:
If RCSTA.OERR = 1 OR RCSTA.FERR = 1 THEN
.
.
.
Oshonsoft usually allows one OR statement in an IF statement. (or one AND statement)
Finally, you cannot write to PIR1.RCIF, it is a read-only register. It is cleared when the RCREG is empty

When you detect an error, you clear it and exit....
If PIR1.RCIF = 1 you do a THEN and put the block of code below it and end it with an ENDIF. The way you have it written, the
"If PIR1.RCIF = 1 Then char = RCREG" only does only one thing, and the rest of the code is executed regardless.
Hi S,
"If RCSTA.OERR = 1 OR RCSTA.FERR = 1 THEN"--------------DONE

"Finally, you cannot write to PIR1.RCIF"-----------------OK.

Regarding PIR1.RCIF. Are you saying that all of my INTERRUPT routine, should be inside an:
[ If PIR1.RCIF = 1 then
..........MY INTERRUPT.......
endif ] ?
C.
 
Top