CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

i2c interrupt routine constantly being called

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
qm
Guest







i2c interrupt routine constantly being called
PostPosted: Thu Jul 24, 2003 12:52 pm     Reply with quote

I'm trying to get my I2C slave code to work using the built in MSSP. My compiler version is 3.110

In short, I want to send three numbers one after the other. They're constant in this code, but I need to change them within the while loop in main().

However, after the first SSP interrupt, the while loop does not continue. In this case, that means the red led stops blinking, and I can't perform any operations in main().

Additionally, the default case in the ISR keeps getting called. As far as I know, it's an illegal condition and shouldn't get called at all, but very quickly the integer b hits its limit at 0xAA (I'm using port b for debugging).

I don't know why the ISR keeps getting called, even after a stop condition. I tried clearing the SSPIF bit myself, but that didn't work, and the compiler should handle that anyway.

Thanks for any help.



#include <16F872.h>
#fuses HS,NOWDT,NOPROTECT,PUT
#use delay(clock=20000000)

// Enable manual setting of directions on ports B and C
#use fast_io(b)
#use fast_io(c)
int8 tris_b = 0b00000000;
int8 tris_c = 0b00011000;

// I2C definitions
#define SDA_PIN PIN_C4 // I2C Serial DAta line
#define SCL_PIN PIN_C3 // I2C Serial Clock Line
#define SDA_DIR 0x87.4 // See PIC16F872 Register File Map
#define SCL_DIR 0x87.3 // See PIC16F872 Register File Map

#define SLAVE_ADDRESS 0xC4
#define MAXPACKETLENGTH 16

// IN THE INTEREST OF BREVITY, I REMOVED ALL THE PIN AND REGISTER DEFINITIONS

void toggle_red(void);
void ssp_interrupt(void);

int i2c_count = 0;
int b = 0;
int8 qpacket[16] = { 0x02, 0x12, 0x34 };


void main() {
int trash;

set_tris_b(tris_b);
set_tris_c(tris_c);

SSPCON = 0;
SSPSTAT = 0;
SSPIF = 0;
trash = SSPBUF; // clear BF

SSPIE = 1; // SSP interrupt enable
PEIE = 1; // Peripheral interrupt enable
GIE = 1; // Global interrupt enable

// Configure I2C
SSPADD = SLAVE_ADDRESS; // Configure address
CKE = 0; // Input levels conform to I2C spec
GCEN = 1; // General Call enable (i.e. respond to broadcast address)
SSPCON = 0b00110110; // SSPM[3:0] = 0110: I2C slave mode, 7-bit address
// CKP = 1: Enable clock (i.e. don't hold it low)
// SSPEN = 1: Enable MSSP module (do this last)

output_b(0);

while(1) {
delay_ms(500);
toggle_red();
}
}

#INT_SSP
void ssp_interrupt(void) {
int8 trash;
if (P) { return; }
switch (SSPSTAT & 0b00101101) { // Only interested in these four bits: D_A, S, R_W, BF
case 0b00001001: // S = 1, R_W = 0, D_A = 0, BF = 1
// Master Write, Last Byte was an Address
SSPOV = 0;
trash = SSPBUF;
break;
case 0b00101001: // S = 1, R_W = 0, D_A = 1, BF = 1
// Master Write, Last Byte was Data
SSPOV = 0;
qpacket[i2c_count] = SSPBUF;
i2c_count++;
if (i2c_count == qpacket[0]+2) {
i2c_count = 0;
}
break;
case 0b00001100: // S = 1, R_W = 1, D_A = 0, BF = 0
// Master Read, Last Byte was an Address
SSPBUF = qpacket[i2c_count];
CKP = 1; // Enable CKP in order to stop pulling SCL low
i2c_count++;
if (i2c_count == qpacket[0]+2) {
i2c_count = 0;
}
break;
case 0b00101100: // S = 1, R_W = 1, D_A = 1, BF = 0
// Master Read, Last Byte was Data
SSPBUF = qpacket[i2c_count];
CKP = 1; // Enable CKP in order to stop pulling SCL low
i2c_count++;
if (i2c_count == qpacket[0]+2) {
i2c_count = 0;
}
break;
case 0b00101000: // S = 1, R_W = 0, D_A = 1, BF = 0
// Master NACK
break;
default: // Invalid condition
b+=1;
if (b >= 0xAA) b = 0xAA;
output_b(b);
}
SSPIF = 0;
}

int redstate = 0;
void toggle_red(void) {
if (redstate) {
redstate= 0;
RED_LED_OFF;
} else {
redstate = 1;
RED_LED_ON;
}
}
___________________________
This message was ported from CCS's old forum
Original Post ID: 144516317
R.J.Hamlett
Guest







Re: i2c interrupt routine constantly being called
PostPosted: Thu Jul 24, 2003 12:59 pm     Reply with quote

:=I'm trying to get my I2C slave code to work using the built in MSSP. My compiler version is 3.110
:=
:=In short, I want to send three numbers one after the other. They're constant in this code, but I need to change them within the while loop in main().
:=
:=However, after the first SSP interrupt, the while loop does not continue. In this case, that means the red led stops blinking, and I can't perform any operations in main().
:=
:=Additionally, the default case in the ISR keeps getting called. As far as I know, it's an illegal condition and shouldn't get called at all, but very quickly the integer b hits its limit at 0xAA (I'm using port b for debugging).
:=
:=I don't know why the ISR keeps getting called, even after a stop condition. I tried clearing the SSPIF bit myself, but that didn't work, and the compiler should handle that anyway.
:=
:=Thanks for any help.
:=
Make your ISR, read the I2C data register, whatever else it does. The ISR, should allways be called, when there is data in the register, but if the register is not read, then the next time, the 'overflow' condition will get set, and things go screwy. At the start of your ISR, you have a test for 'P', and immediately return if this is set. I can't see where you set, or clear this?. If this is somehow set, you don't execute the rest of the code, which should handle the read?.

Best Wishes

:=
:=#include <16F872.h>
:=#fuses HS,NOWDT,NOPROTECT,PUT
:=#use delay(clock=20000000)
:=
:=// Enable manual setting of directions on ports B and C
:=#use fast_io(b)
:=#use fast_io(c)
:=int8 tris_b = 0b00000000;
:=int8 tris_c = 0b00011000;
:=
:=// I2C definitions
:=#define SDA_PIN PIN_C4 // I2C Serial DAta line
:=#define SCL_PIN PIN_C3 // I2C Serial Clock Line
:=#define SDA_DIR 0x87.4 // See PIC16F872 Register File Map
:=#define SCL_DIR 0x87.3 // See PIC16F872 Register File Map
:=
:=#define SLAVE_ADDRESS 0xC4
:=#define MAXPACKETLENGTH 16
:=
:=// IN THE INTEREST OF BREVITY, I REMOVED ALL THE PIN AND REGISTER DEFINITIONS
:=
:=void toggle_red(void);
:=void ssp_interrupt(void);
:=
:=int i2c_count = 0;
:=int b = 0;
:=int8 qpacket[16] = { 0x02, 0x12, 0x34 };
:=
:=
:=void main() {
:= int trash;
:=
:= set_tris_b(tris_b);
:= set_tris_c(tris_c);
:=
:= SSPCON = 0;
:= SSPSTAT = 0;
:= SSPIF = 0;
:= trash = SSPBUF; // clear BF
:=
:= SSPIE = 1; // SSP interrupt enable
:= PEIE = 1; // Peripheral interrupt enable
:= GIE = 1; // Global interrupt enable
:=
:= // Configure I2C
:= SSPADD = SLAVE_ADDRESS; // Configure address
:= CKE = 0; // Input levels conform to I2C spec
:= GCEN = 1; // General Call enable (i.e. respond to broadcast address)
:= SSPCON = 0b00110110; // SSPM[3:0] = 0110: I2C slave mode, 7-bit address
:= // CKP = 1: Enable clock (i.e. don't hold it low)
:= // SSPEN = 1: Enable MSSP module (do this last)
:=
:= output_b(0);
:=
:= while(1) {
:= delay_ms(500);
:= toggle_red();
:= }
:=}
:=
:=#INT_SSP
:=void ssp_interrupt(void) {
:= int8 trash;
:= if (P) { return; }
:= switch (SSPSTAT & 0b00101101) { // Only interested in these four bits: D_A, S, R_W, BF
:= case 0b00001001: // S = 1, R_W = 0, D_A = 0, BF = 1
:= // Master Write, Last Byte was an Address
:= SSPOV = 0;
:= trash = SSPBUF;
:= break;
:= case 0b00101001: // S = 1, R_W = 0, D_A = 1, BF = 1
:= // Master Write, Last Byte was Data
:= SSPOV = 0;
:= qpacket[i2c_count] = SSPBUF;
:= i2c_count++;
:= if (i2c_count == qpacket[0]+2) {
:= i2c_count = 0;
:= }
:= break;
:= case 0b00001100: // S = 1, R_W = 1, D_A = 0, BF = 0
:= // Master Read, Last Byte was an Address
:= SSPBUF = qpacket[i2c_count];
:= CKP = 1; // Enable CKP in order to stop pulling SCL low
:= i2c_count++;
:= if (i2c_count == qpacket[0]+2) {
:= i2c_count = 0;
:= }
:= break;
:= case 0b00101100: // S = 1, R_W = 1, D_A = 1, BF = 0
:= // Master Read, Last Byte was Data
:= SSPBUF = qpacket[i2c_count];
:= CKP = 1; // Enable CKP in order to stop pulling SCL low
:= i2c_count++;
:= if (i2c_count == qpacket[0]+2) {
:= i2c_count = 0;
:= }
:= break;
:= case 0b00101000: // S = 1, R_W = 0, D_A = 1, BF = 0
:= // Master NACK
:= break;
:= default: // Invalid condition
:= b+=1;
:= if (b >= 0xAA) b = 0xAA;
:= output_b(b);
:= }
:= SSPIF = 0;
:=}
:=
:=int redstate = 0;
:=void toggle_red(void) {
:= if (redstate) {
:= redstate= 0;
:= RED_LED_OFF;
:= } else {
:= redstate = 1;
:= RED_LED_ON;
:= }
:=}
___________________________
This message was ported from CCS's old forum
Original Post ID: 144516318
qm
Guest







Re: i2c interrupt routine constantly being called
PostPosted: Thu Jul 24, 2003 1:04 pm     Reply with quote

:=:=I'm trying to get my I2C slave code to work using the built in MSSP. My compiler version is 3.110
:=:=
:=:=In short, I want to send three numbers one after the other. They're constant in this code, but I need to change them within the while loop in main().
:=:=
:=:=However, after the first SSP interrupt, the while loop does not continue. In this case, that means the red led stops blinking, and I can't perform any operations in main().
:=:=
:=:=Additionally, the default case in the ISR keeps getting called. As far as I know, it's an illegal condition and shouldn't get called at all, but very quickly the integer b hits its limit at 0xAA (I'm using port b for debugging).
:=:=
:=:=I don't know why the ISR keeps getting called, even after a stop condition. I tried clearing the SSPIF bit myself, but that didn't work, and the compiler should handle that anyway.
:=:=
:=:=Thanks for any help.
:=:=
:=Make your ISR, read the I2C data register, whatever else it does. The ISR, should allways be called, when there is data in the register, but if the register is not read, then the next time, the 'overflow' condition will get set, and things go screwy. At the start of your ISR, you have a test for 'P', and immediately return if this is set. I can't see where you set, or clear this?. If this is somehow set, you don't execute the rest of the code, which should handle the read?.
:=
:=Best Wishes
:=
:=:=
:=:=#include <16F872.h>
:=:=#fuses HS,NOWDT,NOPROTECT,PUT
:=:=#use delay(clock=20000000)
:=:=
:=:=// Enable manual setting of directions on ports B and C
:=:=#use fast_io(b)
:=:=#use fast_io(c)
:=:=int8 tris_b = 0b00000000;
:=:=int8 tris_c = 0b00011000;
:=:=
:=:=// I2C definitions
:=:=#define SDA_PIN PIN_C4 // I2C Serial DAta line
:=:=#define SCL_PIN PIN_C3 // I2C Serial Clock Line
:=:=#define SDA_DIR 0x87.4 // See PIC16F872 Register File Map
:=:=#define SCL_DIR 0x87.3 // See PIC16F872 Register File Map
:=:=
:=:=#define SLAVE_ADDRESS 0xC4
:=:=#define MAXPACKETLENGTH 16
:=:=
:=:=// IN THE INTEREST OF BREVITY, I REMOVED ALL THE PIN AND REGISTER DEFINITIONS
:=:=
:=:=void toggle_red(void);
:=:=void ssp_interrupt(void);
:=:=
:=:=int i2c_count = 0;
:=:=int b = 0;
:=:=int8 qpacket[16] = { 0x02, 0x12, 0x34 };
:=:=
:=:=
:=:=void main() {
:=:= int trash;
:=:=
:=:= set_tris_b(tris_b);
:=:= set_tris_c(tris_c);
:=:=
:=:= SSPCON = 0;
:=:= SSPSTAT = 0;
:=:= SSPIF = 0;
:=:= trash = SSPBUF; // clear BF
:=:=
:=:= SSPIE = 1; // SSP interrupt enable
:=:= PEIE = 1; // Peripheral interrupt enable
:=:= GIE = 1; // Global interrupt enable
:=:=
:=:= // Configure I2C
:=:= SSPADD = SLAVE_ADDRESS; // Configure address
:=:= CKE = 0; // Input levels conform to I2C spec
:=:= GCEN = 1; // General Call enable (i.e. respond to broadcast address)
:=:= SSPCON = 0b00110110; // SSPM[3:0] = 0110: I2C slave mode, 7-bit address
:=:= // CKP = 1: Enable clock (i.e. don't hold it low)
:=:= // SSPEN = 1: Enable MSSP module (do this last)
:=:=
:=:= output_b(0);
:=:=
:=:= while(1) {
:=:= delay_ms(500);
:=:= toggle_red();
:=:= }
:=:=}
:=:=
:=:=#INT_SSP
:=:=void ssp_interrupt(void) {
:=:= int8 trash;
:=:= if (P) { return; }
:=:= switch (SSPSTAT & 0b00101101) { // Only interested in these four bits: D_A, S, R_W, BF
:=:= case 0b00001001: // S = 1, R_W = 0, D_A = 0, BF = 1
:=:= // Master Write, Last Byte was an Address
:=:= SSPOV = 0;
:=:= trash = SSPBUF;
:=:= break;
:=:= case 0b00101001: // S = 1, R_W = 0, D_A = 1, BF = 1
:=:= // Master Write, Last Byte was Data
:=:= SSPOV = 0;
:=:= qpacket[i2c_count] = SSPBUF;
:=:= i2c_count++;
:=:= if (i2c_count == qpacket[0]+2) {
:=:= i2c_count = 0;
:=:= }
:=:= break;
:=:= case 0b00001100: // S = 1, R_W = 1, D_A = 0, BF = 0
:=:= // Master Read, Last Byte was an Address
:=:= SSPBUF = qpacket[i2c_count];
:=:= CKP = 1; // Enable CKP in order to stop pulling SCL low
:=:= i2c_count++;
:=:= if (i2c_count == qpacket[0]+2) {
:=:= i2c_count = 0;
:=:= }
:=:= break;
:=:= case 0b00101100: // S = 1, R_W = 1, D_A = 1, BF = 0
:=:= // Master Read, Last Byte was Data
:=:= SSPBUF = qpacket[i2c_count];
:=:= CKP = 1; // Enable CKP in order to stop pulling SCL low
:=:= i2c_count++;
:=:= if (i2c_count == qpacket[0]+2) {
:=:= i2c_count = 0;
:=:= }
:=:= break;
:=:= case 0b00101000: // S = 1, R_W = 0, D_A = 1, BF = 0
:=:= // Master NACK
:=:= break;
:=:= default: // Invalid condition
:=:= b+=1;
:=:= if (b >= 0xAA) b = 0xAA;
:=:= output_b(b);
:=:= }
:=:= SSPIF = 0;
:=:=}
:=:=
:=:=int redstate = 0;
:=:=void toggle_red(void) {
:=:= if (redstate) {
:=:= redstate= 0;
:=:= RED_LED_OFF;
:=:= } else {
:=:= redstate = 1;
:=:= RED_LED_ON;
:=:= }
:=:=}
___________________________
This message was ported from CCS's old forum
Original Post ID: 144516319
qm
Guest







Re: i2c interrupt routine constantly being called
PostPosted: Thu Jul 24, 2003 1:07 pm     Reply with quote

:=Make your ISR, read the I2C data register, whatever else it does. The ISR, should allways be called, when there is data in the register, but if the register is not read, then the next time, the 'overflow' condition will get set, and things go screwy. At the start of your ISR, you have a test for 'P', and immediately return if this is set. I can't see where you set, or clear this?. If this is somehow set, you don't execute the rest of the code, which should handle the read?.
:=
:=Best Wishes
:=

Hmm... the message board erased what I wrote in reply...

Sorry, "P" is defined as so:
#bit P =0x94.4 // stop
That is, the 4th bit of the SSPSTAT register
I put that in there to catch any ISR calls after a stop condition, but it doesn't seem to work.

The only case where I'm not touching SSPBUF is the Master NACK case. Should I be doing a dummy read there? In the Master read cases, I'm writing to SSPBUF and setting CKP. Should I be doing something before this in order to prevent an overflow error?
___________________________
This message was ported from CCS's old forum
Original Post ID: 144516320
R.J.Hamlett
Guest







Re: i2c interrupt routine constantly being called
PostPosted: Thu Jul 24, 2003 2:52 pm     Reply with quote

:=:=Make your ISR, read the I2C data register, whatever else it does. The ISR, should allways be called, when there is data in the register, but if the register is not read, then the next time, the 'overflow' condition will get set, and things go screwy. At the start of your ISR, you have a test for 'P', and immediately return if this is set. I can't see where you set, or clear this?. If this is somehow set, you don't execute the rest of the code, which should handle the read?.
:=:=
:=:=Best Wishes
:=:=
:=
:=Hmm... the message board erased what I wrote in reply...
:=
:=Sorry, "P" is defined as so:
:=#bit P =0x94.4 // stop
:=That is, the 4th bit of the SSPSTAT register
:=I put that in there to catch any ISR calls after a stop condition, but it doesn't seem to work.
:=
I don't think the ISR, should ever get called in this case (the data sheet doesn't say that the interrupt flag gets set for the stop bit, so this is redundant). Surely though, the last data byte, will have the 'stop' pattern sent only a few moments latter, adn if the interrupt latency is more than the time needed for this to happen, you would still have a byte needing handling?.

:=The only case where I'm not touching SSPBUF is the Master NACK case. Should I be doing a dummy read there? In the Master read cases, I'm writing to SSPBUF and setting CKP. Should I be doing something before this in order to prevent an overflow error?

You should read the buffer in every case. Even in the NACK case, a byte has been potentially been sent, but in fact the chip won't interrupt, and will then give a buffer overflow error, that has to be checked in the main code (look at the picture of the interrupt events, Fig 9-6, in the MicroChip data sheet). This would cause a problem. Also, what happens if the chip responds to a GCA sequence (you are presumably never sending this, but the handler should be there...)?.
Basically, I allways treat the I2C handler, like the portB change handler, and insert the 'read', no matter what route is taken.

Best Wishes
___________________________
This message was ported from CCS's old forum
Original Post ID: 144516328
qm
Guest







Re: i2c interrupt routine constantly being called
PostPosted: Fri Jul 25, 2003 9:30 am     Reply with quote

:=I don't think the ISR, should ever get called in this case (the data sheet doesn't say that the interrupt flag gets set for the stop bit, so this is redundant). Surely though, the last data byte, will have the 'stop' pattern sent only a few moments latter, adn if the interrupt latency is more than the time needed for this to happen, you would still have a byte needing handling?.

No, the ISR *shouldn't* get called in that case. What I do know is that with the line: if (P) return; does cut the number of times that the default case at the bottom is called.

This means that the ISR is being called multiple times after a stop condition, even though it really shouldn't.

:=You should read the buffer in every case. Even in the NACK case, a byte has been potentially been sent, but in fact the chip won't interrupt, and will then give a buffer overflow error, that has to be checked in the main code (look at the picture of the interrupt events, Fig 9-6, in the MicroChip data sheet). This would cause a problem. Also, what happens if the chip responds to a GCA sequence (you are presumably never sending this, but the handler should be there...)?.

I have the same problems even if I read SSPBUF each time. Once I get the rest of the code working, I'll put the GCA handler back in.

:=Basically, I allways treat the I2C handler, like the portB change handler, and insert the 'read', no matter what route is taken.

Thanks.
___________________________
This message was ported from CCS's old forum
Original Post ID: 144516356
R.J.Hamlett
Guest







Re: i2c interrupt routine constantly being called
PostPosted: Fri Jul 25, 2003 9:37 am     Reply with quote

:=:=I don't think the ISR, should ever get called in this case (the data sheet doesn't say that the interrupt flag gets set for the stop bit, so this is redundant). Surely though, the last data byte, will have the 'stop' pattern sent only a few moments latter, adn if the interrupt latency is more than the time needed for this to happen, you would still have a byte needing handling?.
:=
:=No, the ISR *shouldn't* get called in that case. What I do know is that with the line: if (P) return; does cut the number of times that the default case at the bottom is called.
:=
:=This means that the ISR is being called multiple times after a stop condition, even though it really shouldn't.
:=
You are missing the point of what I say.
Remember that time has elapsed between the interrupt occurring, and you arriving in the ISR. This can be a lot longer than you think (often 50+ instruction times, or more if there is a main function, that has a long section with interrupts disabled...). Now what can happen, is that the interrupt flag gets set, and then some micro seconds latter the 'P' flag gets set, before you arrive at your handler. Now because of your test, you return immediately, without reading the character. This will effectively loose the character that should have been read, and then result in the overrun flag being set with the next character....

:=:=You should read the buffer in every case. Even in the NACK case, a byte has been potentially been sent, but in fact the chip won't interrupt, and will then give a buffer overflow error, that has to be checked in the main code (look at the picture of the interrupt events, Fig 9-6, in the MicroChip data sheet). This would cause a problem. Also, what happens if the chip responds to a GCA sequence (you are presumably never sending this, but the handler should be there...)?.
:=
:=I have the same problems even if I read SSPBUF each time. Once I get the rest of the code working, I'll put the GCA handler back in.
:=
Are you clearing the overrun flag in the main code?. If you use 'nack', this flag _will_ get set, without an interrupt, and then the flag needs to be cleared.

:=:=Basically, I allways treat the I2C handler, like the portB change handler, and insert the 'read', no matter what route is taken.
:=
:=Thanks.

Best Wishes
___________________________
This message was ported from CCS's old forum
Original Post ID: 144516357
qm
Guest







Re: i2c interrupt routine constantly being called
PostPosted: Fri Jul 25, 2003 10:10 am     Reply with quote

:=You are missing the point of what I say.
:=Remember that time has elapsed between the interrupt occurring, and you arriving in the ISR. This can be a lot longer than you think (often 50+ instruction times, or more if there is a main function, that has a long section with interrupts disabled...). Now what can happen, is that the interrupt flag gets set, and then some micro seconds latter the 'P' flag gets set, before you arrive at your handler. Now because of your test, you return immediately, without reading the character. This will effectively loose the character that should have been read, and then result in the overrun flag being set with the next character....

well, I removed that line of code, but it doesn't help any. I guess I don't understand why the P flag would be set just after an interrupt. The master is certainly receiving the acknowledge, so it wouldn't terminate the transfer until after the data byte is sent. So, I don't see why P would be set *before* SSPBUF is written.

:=Are you clearing the overrun flag in the main code?. If you use 'nack', this flag _will_ get set, without an interrupt, and then the flag needs to be cleared.

I am clearing the overrun flag (you mean SSPOV, right?) in the main code. however, the main loop is only run a few times at the beginning, for some reason it stops running as soon as it gets its first I2C event.

Thanks again, for your time.
___________________________
This message was ported from CCS's old forum
Original Post ID: 144516360
R.J.Hamlett
Guest







Re: i2c interrupt routine constantly being called
PostPosted: Fri Jul 25, 2003 12:53 pm     Reply with quote

:=:=You are missing the point of what I say.
:=:=Remember that time has elapsed between the interrupt occurring, and you arriving in the ISR. This can be a lot longer than you think (often 50+ instruction times, or more if there is a main function, that has a long section with interrupts disabled...). Now what can happen, is that the interrupt flag gets set, and then some micro seconds latter the 'P' flag gets set, before you arrive at your handler. Now because of your test, you return immediately, without reading the character. This will effectively loose the character that should have been read, and then result in the overrun flag being set with the next character....
:=
:=well, I removed that line of code, but it doesn't help any. I guess I don't understand why the P flag would be set just after an interrupt. The master is certainly receiving the acknowledge, so it wouldn't terminate the transfer until after the data byte is sent. So, I don't see why P would be set *before* SSPBUF is written.
:=
It wouldn't. Where do I say it would?..
Remember the interrupt is set on the 9th bit of the data byte on receive. The point is that potentially, the interrupt could occur, and the P flag, could be set, _before_ the handler actually executes. The fact that turning off the P test, increases the number of times the core function is called, implies that something like this is happening.

:=:=Are you clearing the overrun flag in the main code?. If you use 'nack', this flag _will_ get set, without an interrupt, and then the flag needs to be cleared.
:=
:=I am clearing the overrun flag (you mean SSPOV, right?) in the main code. however, the main loop is only run a few times at the beginning, for some reason it stops running as soon as it gets its first I2C event.
:=
:=Thanks again, for your time.
Try something like this:
#bit SSPOV=0x14.6
#bit BF=0x94.0
#bit CKP=0x14.4
#bit RW=0x94.2
#bit ADDR=0x94.5

#INT_SSP
void ssp_interrupt(void) {
int8 trash;
/*There are only three legitimate conditions:
BF SSPOV
0 0
1 0
1 1
Also the 'error' condition, of
0 1 */
if (BF) {
trash=SSPBUF;
//ensure there is a read
//Here I may have data or an address
if (ADDR) {
if (!RW) {
//Here I have to write the data back, and clear the clock
i2c_count=0;
//reset buffer pointer
SSPBUF=qpacket[i2c_count];
CKP=1;
}
else
{
//There is data to read here, if required, copy 'trash' to store
}
}
else {
//Here I should send the next outgoing character
SSPBUF=qpacket[++i2c_count];
CKP=1;
}
if (SSPOV) SSPOV=0;
}

Best Wishes
___________________________
This message was ported from CCS's old forum
Original Post ID: 144516366
qm
Guest







Re: i2c interrupt routine constantly being called
PostPosted: Fri Jul 25, 2003 3:26 pm     Reply with quote

<font face="Courier New" size=-1>:=It wouldn't. Where do I say it would?..
:=Remember the interrupt is set on the 9th bit of the data byte on receive. The point is that potentially, the interrupt could occur, and the P flag, could be set, _before_ the handler actually executes. The fact that turning off the P test, increases the number of times the core function is called, implies that something like this is happening.


sorry, I misunderstood.

the code you sent works as I'd expect it to (though I added a curly brace that was missing). I can get the master to read the data bytes over the I2C as many times as I like.

what I don't understand is why the ISR never seems to return to the loop in main(), and why the ISR seems to be called hundreds of times for each I2C transaction, when it should only be called once per byte or so.

Here's my code for main, in this case I'm just trying to put 8 bits from the ADC into qpacket[0] every 1/2 second or so. However, after the first I2C transaction, qpacket[0] never gets updated, and the red led stops blinking.

thanks, again. I'm sorry to be a bother.

void main() {
int trash;

set_tris_b(tris_b);
set_tris_c(tris_c);

setup_port_a( ALL_ANALOG );
setup_adc( ADC_CLOCK_INTERNAL );
set_adc_channel( 0 );
//WARNING, wait about 10us after each channel change!!!
//See PICC help on SET_ADC_CHANNEL()


SSPCON = 0;
SSPSTAT = 0;
SSPIF = 0;
trash = SSPBUF; // clear BF

SSPIE = 1; // SSP interrupt enable
PEIE = 1; // Peripheral interrupt enable
GIE = 1; // Global interrupt enable

// Configure I2C
SSPADD = SLAVE_ADDRESS; // Configure address
CKE = 0; // Input levels conform to I2C spec
GCEN = 1; // General Call enable (i.e. respond to broadcast address)
SSPCON = 0b00110110; // SSPM[3:0] = 0110: I2C slave mode, 7-bit address
// CKP = 1: Enable clock (i.e. don't hold it low)
// SSPEN = 1: Enable MSSP module (do this last)

while(1) {
toggle_red();
delay_ms(500);
qpacket[0] = read_adc();
}
}</font>
___________________________
This message was ported from CCS's old forum
Original Post ID: 144516375
qm
Guest







Re: i2c interrupt routine constantly being called
PostPosted: Wed Aug 06, 2003 1:08 pm     Reply with quote

for a hacked solution to this problem look at this thread:
<a href="http://www.pic-c.com/forum/general/posts/144516659.html" TARGET="_blank">http://www.pic-c.com/forum/general/posts/144516659.html</a>
___________________________
This message was ported from CCS's old forum
Original Post ID: 144516725
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group