Hi there,
I have been working on pic16F877A for a while, and I found that there is some problem with its MSSP module when used in slave mode. My experiment is as follows-
I have atmega128 as master and PIC16F877A as slave. I want slave to transmit few bytes to master on request and interpret(switch on/off set of loads) a byte while in WRITE mode. After initializing the I2C in both the devices, I see that master is doing its work perfectly fine, but the slave doesn't seem to receive anything as it's SSPIF flag doesn't get set which then calls ISR. This, I verified by manually setting SSPIF, and printing a character through UARTwriteChar in ISR, works fine.
I am trying to write a character 'c' (actually random byte) via I2C from master to slave continuously as long as it gets the ACK from slave, i.e. when I2C lines are removed master stops writing.
So, either slave is not receiving anything which is not true since its ACK is sent, Or it receives the data and sends the ACK but there is problem with setting the SSPIF flag after receiving data.
Is there a problem with the internal settings of PIC16 related to I2C or am I missing something important?
Following are the codes-
Code C - [expand] |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
| void I2C_INIT(void)
{
TRISCbits.TRISC3 = 1; /* SDA and SCL as input pin */
TRISCbits.TRISC4 = 1; /* these pins can be configured either i/p or o/p */
SSPCON1bits.SSPM3 = 0;
SSPCON1bits.SSPM2 = 1; // SLAVE mode with 7bit address
SSPCON1bits.SSPM1 = 1;
SSPCON1bits.SSPM0 = 0;
SSPSTATbits.SMP = 0; // Slew rate set to NORMAL/STANDARD speed @ 100kHz
SSPADD = I2C_ADDR; // SLAVE address is (7bit). Lsb is R/W flag bit
SSPSTATbits.CKE = 0; // Disable SMBus
SSPCON1bits.SSPEN = 1; // Enable I2C Master port
SSPCON1bits.SSPOV = 0; // Clear Buffer Overflow
SSPCON1bits.CKP = 1; // Clock Released
SSPCON2bits.SEN = 1; // Clock stretching is enabled
INTCONbits.PEIE = 1; // Enable peripheral interrupts
INTCONbits.GIE = 1; // Enable global interrupts
PIR1bits.SSPIF = 0; // reset MSSP interrupt flag bit
PIE1bits.SSPIE = 1; // Enable serial port interrupts
BCLIF = 0; // Clear the bus collision interrupt flag
BCLIE = 1; // Enable bus collision interrupts
}
void interrupt ISR(void)
{
if(SSPIF)
{
USARTWriteChar('a');
if(!SSPSTATbits.R_nW) // read or write can be known from lsb of ADDRESS BYTE
{
if(SSPSTATbits.D_nA)
{
CommandByte = SSPBUF; // get data
USARTWriteChar('(');
OBCcommandresponse();
//USARTWriteChar(CommandByte);
USARTWriteChar(')');
}
if(!SSPSTATbits.D_nA)
{
USARTWriteChar('<');
sendHM_data();
USARTWriteChar('>');
}
}
}
if (BCLIF) // Did a bus collision occur? usually in master mode
{
crap = SSPBUF; // dummy read SSPBUF to clear BF bit
BCLIF = 0; // clear bus collision Int Flag bit
SSPCONbits.CKP = 1; // Release CLK
}
SSPIF = 0;
}
void main()
{
USARTInit(9600);
USARTWriteChar('b');
I2C_INIT();
//SSPIF = 1;
while(1)
{
}
} |
Any kind of help is appreciated.