PDA

View Full Version : USART interrupt not interrupting right



Morpheus
- 1st March 2005, 23:15
Hi All!

I'm working with a 16f628A

I wrote a "simple" code, the interrupt has just to turn on a led when a 9-bit char with the 9th bit enabled is received on the usart rx port.

the main program just make blinking a led.
the results are that if I receive an address(8 bit char with the 9th bit set), the blinking led remains on(or off) doubling the time(2 secs instead 1), and the led that the interrupt had to turn on, remains off.

I'll post my code.

CODE:
----------------------------------------------------------------------
INCLUDE "MODEDEFS.BAS"

TRISA=%11110000
TRISB=%00000010

cmcon=7 ' predispone la portaA come I/O digitali


'INTCON ( Interruption Control register )
intcon.7=1 'GIE : Global Interrupt Enable bit
intcon.6=1 'PEIE : Peripheral Interrupt Enable bit ( This bit should be set when using the CCP interruption so on )
intcon.5=0 'T0IE : TMR0 Overflow Interrupt Enable bit
intcon.4=0 'INTE : RB0/INT Interrupt Enable bit
intcon.3=0 'RBIE : RB Port Change Interrupt Enable bit
intcon.2=0 'T0IF : TMR0 Overflow Interrupt Flag bit
intcon.1=0 'INTF : RB0/INT Interrupt Flag bit
intcon.0=0 'RBIF : RB Port Change Interrupt Flag bit

'definisco il registro di ricezione RCSTA
rcsta.7=1 'SPEN serial port enable bit
rcsta.6=1 'RX9 9-bit receive enable bit
rcsta.5=0 'SREN single receive enable bit
rcsta.4=1 'CREN continous receive enable bit
rcsta.3=1 'ADDEN address detect enable bit
rcsta.2=0 'FERR framing error bit(read only)
rcsta.1=0 'OERR overrun error bit(read only)
rcsta.0=0 'RX9D 9th bit of receive data (read only)


'definisco il registro di trasmissione TXSTA
txsta.7=0 'CSRC : Clock Source Select bit
txsta.6=0 'TX9 : 9-bit Transmit Enable bit
txsta.5=1 'TXEN : Transmit Enable bit
txsta.4=0 'SYNC : USART Mode Select bit 0=asincrono
txsta.3=0 ' N/A
txsta.2=1 'BRGH : High Baud Rate Select bit
txsta.1=0 'TRMT : Transmit Shift Register Status bit ( Read only )
txsta.0=0 'TX9D : 9th bit of transmit data. Can be parity bit.


'PIE1 ( Peripheral Interrupt Enable register ) 8Ch
PIE1.7=0 'EEIE : EE Write Complete Interrupt Enable Bit
PIE1.6=0 'CMIE : Comparator Interrupt Enable bit
PIE1.5=1 'RCIE : USART Receive Interrupt Enable bit
PIE1.4=0 'TXIE : USART Transmit Interrupt Enable bit
PIE1.3=0 ' N/A
PIE1.2=0 'CCP1IE : CCP1 Interrupt Enable bit
PIE1.1=0 'TMR2IE : TMR2 to PR2 Match Interrupt Enable bit
PIE1.0=0 'TMR1IE : TMR1 Overflow Interrupt Enable bit


'azzera tutti i flag di interrupt
PIR1.7=0
PIR1.6=0
PIR1.5=0 'azzera l'RCIF
PIR1.4=0
PIR1.3=0
PIR1.2=0
PIR1.1=0
PIR1.0=0



'DEFINE HSER_BAUD 38400 ' Set baud rate
'DEFINE HSER_SPBRG 15 ' Set SPBRG directly (normally set by HSER_BAUD)

'setta la velocità a 38800
SPBRG.7=0
SPBRG.6=0
SPBRG.5=0
SPBRG.4=0
SPBRG.3=1
SPBRG.2=1
SPBRG.1=1
SPBRG.0=1



DEFINE OSC 10




Enable interrupt


i VAR WORD
led VAR BIT
led2 VAR BIT
ric VAR BYTE



on interrupt GoTo indirizzo

GoTo ricevi


indirizzo:

' HSerin [ric]'riceve un carattere da seriale
' IF led2=1 Then
' PORTA.0=0:led2=0
' Else
' PORTA.0=1:led2=1
' EndIF
PORTB.7=1

Resume


ricevi:

For i=1 to 65000
Next

IF led=1 Then
PORTB.6=0:led=0
Else
PORTB.6=1:led=1
EndIF
GoTo ricevi

-------------------------------------------------------------------
/CODE


I hope someone can help me..
Thanks,
Simone
P.S. Sorry for my english!

Bruce
- 2nd March 2005, 02:31
You always want to clear interrupt flag bits before re-enabling interrupts.
RCIF is the serial receive interrupt flag.

Since RCIF is read-only, you need to read RCREG until it's empty to clear
RCIF. You'll also want to clear any over-run conditions.



OERR VAR RCSTA.1 ' Alias USART over-run bit
CREN VAR RCSTA.4 ' Alias USART continuous receive enable bit
RCIF VAR PIR1.5 ' Alias USART received character interrupt flag bit

Try adding this to your BASIC interrupt routine.


DISABLE
indirizzo:
PORTB.7 = PORTB.7 ^ 1 ' Toggle LED on entry to int handler
IF OERR = 1 THEN ' If over-run, then clear it
CREN = 0 ' Disable receive
CREN = 1 ' Re-enable & clear over-run condition
ENDIF
WHILE RCIF ' If RCIF is set, then read RCREG until it's clear
X = RCREG
WEND
RESUME
ENABLE

Morpheus
- 3rd March 2005, 18:08
Thank you Bruce for the answer, now the pic is interrupting, but I have a problem reading the register right..



indirizzo:

ric = RCREG


While RCIF 'to be sure that the register'll be empty the next time I am going to read it
ric2=RCREG
Wend

IF OERR = 1 Then ' If over-run, then clear it
CREN = 0 ' Disable receive
CREN = 1 ' Re-enable & clear over-run condition
EndIF


'print the first 3 bit of the received char on three external leds
PORTA.0=ric.2
PORTB.7=ric.1
PORTB.6=ric.0


Write 0+X,ric 'write the received byte in the eeprom
X=X+1



Resume
Enable


I am just sending to the pic a 9-bit char like this: 1 0000 0001
the 9th bit generate the interrupt, and "ric" has to be 1.
so at the end I have to read X locations of my eeprom programmed with a "01h" byte.

in the fact I have only the 40-50% of the x locations with 01, and the others has a random-like value (FF, E9, 9b, FE......).

naturally the problem is not on writing the eeprom, because the 3 external led shows that the byte is far from "01h"!!!

I can't explain why this happens, do you?

Thanks a lot
Simone.

Bruce
- 3rd March 2005, 18:24
If you need the 9th bit, then simply read it from RCSTA.0 (as shown in your datasheet) before reading RCREG.

Example;

Received 9-bit data = %1 1010 0011

ric var word

ric.HighByte = RCSTA & %00000001 ' Read RCSTA bit #0 into ric bit #8
ric.LowByte = RCREG

ric now contains %0000 0001 1010 0011

Morpheus
- 3rd March 2005, 19:06
sorry, I think I didn't explain myself well..

I don't need the 9th bit, it works well 'cause I need it just to interrupt the pic.
I need to read the correct address, but I don't know why the char is not always correct.

for example in 10 sended char, 10 times that the pic generates the interrupt and 10 times that i've the rcreg in the var ric. But "ric" contains only 4-5 times the char that I've sent (00000001), the other times it contains random values. The char that I've received is non the one I've sent!!!
I tryed with the "Hserin [ric]" command instead ric=RCREC, but it's the same.

I used the Usart port well without interrupt before, with the same speed (38400) and the received char was ALWAYS correct. I can't explain myself why now I've this problem!!
I took all the last night trying to solve this problem, without success.

Bruce
- 3rd March 2005, 19:16
Are your data packets coming in *all together* or is there a delay between each 9-bit packet?

Are you 100% sure the transmitting device is sending 9-bit packets?

Morpheus
- 3rd March 2005, 19:36
The device (pc) is sending 9-bit packet,
I am sure that it works because if I send a packet with the 9th bit =1, it interrupts, if the 9th bit is=0 it don't.

the device is sending just 1 byte for time. I just made a program that has a button. every click on this button sends a 9-bit packet to the serial port.
I can choose the byte sent, and I can choose if the 9th bit is set or nope.
I also tested it with an oscilloscope. And the 9 bits are correct.

Bruce
- 3rd March 2005, 20:57
I have used 9-bit, but not for sending *all* of my packets as 9-bits.

The address is 9-bits. This issues a wake-up call to all slaves on a common serial bus by generating the hardware interrupt.

All slaves are interrupted, but only the one with the matching address responds.

The addressed slave then turns off 9-bit address detection (ADEN = 0), drops into a receive *data* routine, receives & buffers data until an EOM (end of message) marked is received.

All other slave leave 9-bit address detection ON so they will ignore all data being sent to the salve that was addressed.

Then the addressed slave re-sets back to 9-bit for auto address detection, and carries on until interrupted again.

Are you sending *all* of your data from the PC in 9-bit packets with a 1 in bit position 8? Or only the first byte, then clearing this position to 0 for the remainder of your packets?

If you are, are you clearing ADEN after the address to receive data?

Morpheus
- 3rd March 2005, 23:35
Now I'm not interested on data packets. I'm just trying to address one slave, so the only thing that I'm doing is to send JUST ONE BYTE on the serial port.
This byte is the address byte. If the slave is addressed, he has to do something(to turn on a led?), otherwise he will resume.
I tried to do this, but he worked only in the 40% of the sent bytes.

So I wrote that code to save in the eeprom what char the pic was receiving. And I saw that the char was right only 40% of times.

For example:
-1st try
PC: %1 0000 0001
PIC: interrupt, read RCREG, received char:%0000 0001 (this is right)

-2nd try
PC: %1 0000 0001
PIC: interrupt, read RCREG, received char:%0110 0111 (????????? whi????)

-3rd try:
PC: %1 0000 0001
PIC: interrupt, read RCREG, received char:%0000 0001 (this is right)

-4th
PC: %1 0000 0001
PIC: interrupt, read RCREG, received char:%0100 1001 (????????? whi????)

-5th
PC: %1 0000 0001
PIC: interrupt, read RCREG, received char:%0011 0101 (????????? whi????)

-6th
PC: %1 0000 0001
PIC: interrupt, read RCREG, received char:%0111 0111 (????????? whi????)


....
and so on...
The idea of sending the data byte with only 8 bits is ok, but, for the moment I'm just testing the address detection..
But if I send 1 byte, and when I read it this is not the byte I sent, even if the ninth bit has generated the interrupt, the slave will not work because it thinks it's not addressed!!

The problem is that I'm expecting a byte in the RCREG and what I find is another one (random?). I don't know if this depends on the registers or what, but testing with an oscilloscope on the USART rx pin, the byte is right, and is just ONE! It's so strange he gives me a completely different value!

Is possible that when the pic saves the registers going in interrupt, he changes the value of the RCREG?

Bruce
- 4th March 2005, 00:15
Please post the code you're working with, and I'll have a look

Morpheus
- 4th March 2005, 00:52
Thank you for your patience..



INCLUDE "MODEDEFS.BAS"



TRISA=%11110000
TRISB=%00000010

cmcon=7 ' predispone la portaA come I/O digitali


'INTCON ( Interruption Control register )
intcon.7=1 'GIE : Global Interrupt Enable bit
intcon.6=1 'PEIE : Peripheral Interrupt Enable bit ( This bit should be set when using the CCP interruption so on )
intcon.5=0 'T0IE : TMR0 Overflow Interrupt Enable bit
intcon.4=0 'INTE : RB0/INT Interrupt Enable bit
intcon.3=0 'RBIE : RB Port Change Interrupt Enable bit
intcon.2=0 'T0IF : TMR0 Overflow Interrupt Flag bit
intcon.1=0 'INTF : RB0/INT Interrupt Flag bit
intcon.0=0 'RBIF : RB Port Change Interrupt Flag bit

'definisco il registro di ricezione RCSTA
rcsta.7=1 'SPEN serial port enable bit
rcsta.6=1 'RX9 9-bit receive enable bit
rcsta.5=0 'SREN single receive enable bit
rcsta.4=1 'CREN continous receive enable bit
rcsta.3=1 'ADDEN address detect enable bit
rcsta.2=0 'FERR framing error bit(read only)
rcsta.1=0 'OERR overrun error bit(read only)
rcsta.0=0 'RX9D 9th bit of receive data (read only)


'definisco il registro di trasmissione TXSTA
txsta.7=0 'CSRC : Clock Source Select bit
txsta.6=0 'TX9 : 9-bit Transmit Enable bit
txsta.5=1 'TXEN : Transmit Enable bit
txsta.4=0 'SYNC : USART Mode Select bit 0=asincrono
txsta.3=0 ' N/A
txsta.2=1 'BRGH : High Baud Rate Select bit
txsta.1=0 'TRMT : Transmit Shift Register Status bit ( Read only )
txsta.0=0 'TX9D : 9th bit of transmit data. Can be parity bit.


'PIE1 ( Peripheral Interrupt Enable register ) 8Ch
PIE1.7=0 'EEIE : EE Write Complete Interrupt Enable Bit
PIE1.6=0 'CMIE : Comparator Interrupt Enable bit
PIE1.5=1 'RCIE : USART Receive Interrupt Enable bit
PIE1.4=0 'TXIE : USART Transmit Interrupt Enable bit
PIE1.3=0 ' N/A
PIE1.2=0 'CCP1IE : CCP1 Interrupt Enable bit
PIE1.1=0 'TMR2IE : TMR2 to PR2 Match Interrupt Enable bit
PIE1.0=0 'TMR1IE : TMR1 Overflow Interrupt Enable bit


'azzera tutti i flag di interrupt
PIR1.7=0
PIR1.6=0
PIR1.5=0 'azzera l'RCIF
PIR1.4=0
PIR1.3=0
PIR1.2=0
PIR1.1=0
PIR1.0=0



'DEFINE HSER_BAUD 38400 ' Set baud rate
'DEFINE HSER_SPBRG 15 ' Set SPBRG directly (normally set by HSER_BAUD)

'set the speet to 38800 baud (with a 10Mhz osc)
SPBRG.7=0
SPBRG.6=0
SPBRG.5=0
SPBRG.4=0
SPBRG.3=1
SPBRG.2=1
SPBRG.1=1
SPBRG.0=1



DEFINE OSC 10


OERR VAR RCSTA.1 ' Alias USART over-run bit
CREN VAR RCSTA.4 ' Alias USART continuous receive enable bit
RCIF VAR PIR1.5 ' Alias USART received character interrupt flag bit
ADEN VAR RCSTA.3



Enable interrupt


i VAR WORD
led VAR BIT
led2 VAR BIT
ric VAR BYTE
ric2 VAR BYTE
X VAR BYTE
X=0


on interrupt GoTo indirizzo

GoTo ricevi


Disable
indirizzo:

ric = RCREG 'store the byte contained on RCREG in "ric" and clear RCREG


While RCIF 'to be sure that the register'll be empty the next time I'll read it
ric2=RCREG
Wend

' ADEN=0
' RCIF=0

IF OERR = 1 Then ' If over-run, then clear it
CREN = 0 ' Disable receive
CREN = 1 ' Re-enable & clear over-run condition
EndIF

'print the 3 lsb of ric into 3 external leds
PORTA.0=ric.2
PORTB.7=ric.1
PORTB.6=ric.0

'every time that the pic is interrupted, store the received byte in a location into the eeprom
Write 0+X,ric
X=X+1 'next time will write the next location

Resume
Enable


ricevi:

For i=1 to 65000
Next

IF led=1 Then
PORTA.1=0:led=0
Else
PORTA.1=1:led=1
EndIF
GoTo ricevi

Bruce
- 4th March 2005, 04:19
Try this. It's tested on a 16F627a @4MHz using the MicroCode Studio terminal program.

I suspect your problem may be due to data-rate errors & trying to write to EEPROM with interrupts enabled. This works perfectly at a data-rate of 19,200 @ 4MHz.

Use a PC RS232 terminal program that will allow you to send/receive with odd or even parity & view the results on your terminal program. The PIC is setup to send & receive 9-bit.

This will echo the received address byte back to the PC terminal software using 9-bit send & receive 9-bit with auto address detect. An LED on RB0 will toggle only when in the interrupt service routine.

Note: If you have your PC terminal software set for EVEN parity, then the program (PIC) will only respond to 1,2,4,7 or 8 because these values will generate a logic 1 as the parity bit which the PIC *must* see in 9-bit mode.

If you set it for ODD parity, the PIC will only respond to 3,5,6,9 or 0.

Any value sent to the PIC that does not generate a logic 1 as the 9th parity bit will be ignored, and no interrupt will be generated.



DEFINE OSC 4

OERR VAR RCSTA.1 ' (Read Only) USART over-run bit
CREN VAR RCSTA.4 ' Alias USART continuous receive enable bit
RCIF VAR PIR1.5 ' (Read Only) USART received character interrupt flag bit
ADEN VAR RCSTA.3 ' Alias Address enable bit (for 9-bit mode)
X VAR BYTE ' GP
PORTB.0 = 0 ' Initialize port bit
TRISB.0 = 0 ' RB0 = LED interrupt indicator

'INTCON ( Interruption Control register )
intcon.7=1 'GIE : Global Interrupt Enable bit
intcon.6=1 'PEIE : Peripheral Interrupt Enable bit ( This bit should be set when using the CCP interruption so on )
intcon.5=0 'T0IE : TMR0 Overflow Interrupt Enable bit
intcon.4=0 'INTE : RB0/INT Interrupt Enable bit
intcon.3=0 'RBIE : RB Port Change Interrupt Enable bit
intcon.2=0 'T0IF : TMR0 Overflow Interrupt Flag bit
intcon.1=0 'INTF : RB0/INT Interrupt Flag bit
intcon.0=0 'RBIF : RB Port Change Interrupt Flag bit

'definisco il registro di ricezione RCSTA
rcsta.7=1 'SPEN serial port enable bit
rcsta.6=1 'RX9 9-bit receive enable bit
rcsta.5=0 'SREN single receive enable bit
rcsta.4=1 'CREN continous receive enable bit
rcsta.3=1 'ADDEN address detect enable bit
rcsta.2=0 'FERR framing error bit(read only)
rcsta.1=0 'OERR overrun error bit(read only)
rcsta.0=0 'RX9D 9th bit of receive data (read only)

'definisco il registro di trasmissione TXSTA
txsta.7=0 'CSRC : Clock Source Select bit
txsta.6=1 'TX9 : 9-bit Transmit Enable bit
txsta.5=1 'TXEN : Transmit Enable bit
txsta.4=0 'SYNC : USART Mode Select bit 0=asincrono
txsta.3=0 ' N/A
txsta.2=1 'BRGH : High Baud Rate Select bit
txsta.1=0 'TRMT : Transmit Shift Register Status bit ( Read only )
txsta.0=1 'TX9D : 9th bit of transmit data. Can be parity bit.

'PIE1 ( Peripheral Interrupt Enable register ) 8Ch
PIE1.7=0 'EEIE : EE Write Complete Interrupt Enable Bit
PIE1.6=0 'CMIE : Comparator Interrupt Enable bit
PIE1.5=1 'RCIE : USART Receive Interrupt Enable bit
PIE1.4=0 'TXIE : USART Transmit Interrupt Enable bit
PIE1.3=0 ' N/A
PIE1.2=0 'CCP1IE : CCP1 Interrupt Enable bit
PIE1.1=0 'TMR2IE : TMR2 to PR2 Match Interrupt Enable bit
PIE1.0=0 'TMR1IE : TMR1 Overflow Interrupt Enable bit

SPBRG = 12 ' 19,200 bps @ 4MHz 16F627a

ON INTERRUPT GOTO IntHandler

Main:
FOR X = 0 TO 255 ; Waste some time waiting for characters
PAUSEUS 10
NEXT
GOTO Main

DISABLE
IntHandler:
PORTB.0 = PORTB.0^1 ' Indicate that we are in interrupt routine
IF RCIF THEN ; Read characters from RCREG only when RCIF is set
@ movf RCREG, W ; Load RCREG into W
@ movwf TXREG ; Transmit back to PC
ENDIF
' Clear over-runs if present
IF OERR = 1 Then ' If over-run, then clear it
CREN = 0 ' Disable receive
CREN = 1 ' Re-enable & clear over-run condition
EndIF
Resume
Enable
END

Morpheus
- 6th March 2005, 01:07
It's not possible!
You can't believe where was the problem!
It was a hardware problem!!:
I'm using a rs485 net, and there was a short-circuit on the Tx-enable pin of my rs485 converter..
so the char I was reading was noised by strange trasmissions on the line!!! the char I were sending was right, but the received one was mixed with other stranges things..

sorry. The program was working right.
Thank you Bruce for your attention.
C yA
Simone.