My problem is when SSP1CON2bits.ACKDT = 1; the master recive the corect data, sends an ACK then stops, (see second pic) I think the master stops completely. Some how, somewhere I think I'm missing a register in wrong setting.
Slave:
- Code: Select all
/* Simple I2C slave example, in this simple state the program halt the chip until address and everything match
* Plus transmit only one byte. See Simple I2C Master */
// PIC16F1829 Configuration Bit Settings
#pragma config FOSC = INTOSC // Oscillator Selection (INTOSC oscillator: I/O function on CLKIN pin)
#pragma config WDTE = OFF // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = OFF // Power-up Timer Enable (PWRT disabled)
#pragma config MCLRE = ON // MCLR Pin Function Select (MCLR/VPP pin function is MCLR)
#pragma config CP = OFF // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config CPD = OFF // Data Memory Code Protection (Data memory code protection is disabled)
#pragma config BOREN = ON // Brown-out Reset Enable (Brown-out Reset enabled)
#pragma config CLKOUTEN = ON // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)
#pragma config IESO = ON // Internal/External Switchover (Internal/External Switchover mode is enabled)
#pragma config FCMEN = ON // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is enabled)
#pragma config WRT = OFF // Flash Memory Self-Write Protection (Write protection off)
#pragma config PLLEN = OFF // Disabled, see OSCCON
#pragma config STVREN = ON // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset)
#pragma config BORV = LO // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config LVP = OFF // Low-Voltage Programming Enable (Low-voltage programming enabled)
// #pragma config statements should precede project file includes.
#include <xc.h>
#define _XTAL_FREQ 32000000
#ifndef _i2cSDA
#define _i2cSDA TRISBbits.TRISB4
#endif
#ifndef _i2cCLK
#define _i2cCLK TRISBbits.TRISB6
#endif
void initI2C(void);
void interrupt slaveI2Csend (void);
unsigned char mumu=0;
void main(void) {
OSCCON=0b11110000;
_i2cSDA=1;
_i2cCLK=1;
initI2C();
while(1); //interrupt test
return;
}
void initI2C(void){
ANSELB=0;
SSP1STATbits.SMP=1; //slew rate enabled
SSP1STATbits.CKE=0; //no SMB needed
SSP1CON1bits.SSPM3=1; //slave i2c, 7bit address
SSP1CON1bits.SSPM2=1; //slave i2c, 7bit address
SSP1CON1bits.SSPM1=1; //slave i2c, 7bit address
SSP1CON1bits.SSPM0=0; //slave i2c, 7bit address
//Slave address chosen is E (Encoder) 0x45 (dec: 69) 0b10001010(last bit is unused)
SSP1ADD=0b10001010;
SSP1CON1bits.SSPEN = 1; //enable I2C module
PIE1bits.SSP1IE = 1;
INTCONbits.PEIE = 1;
INTCONbits.GIE = 1; //interrupt active again
return;
}
void interrupt slaveI2Csend (void){
if (PIR1bits.SSP1IF) { //make sure that SSP1 address match brought us here, do no handle any other interrupt
PIR1bits.SSP1IF=0;
SSP1BUF; //clear buffer to prepare for next transfer
if (SSP1STATbits.R_nW){ //master wants to read
mumu=mumu+1u;
SSP1BUF = mumu; //load data
}
}
SSP1CON1bits.CKP=1; //release clock to transmit data to master
}
Master:
- Code: Select all
/* Simple I2C slave example, in this simple state the program halt the chip until address and everything match
* Plus transmit only one byte. See Simple I2C Slace */
// PIC16F1829 Configuration Bit Settings
#pragma config FOSC = INTOSC // Oscillator Selection (INTOSC oscillator: I/O function on CLKIN pin)
#pragma config WDTE = OFF // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = OFF // Power-up Timer Enable (PWRT disabled)
#pragma config MCLRE = ON // MCLR Pin Function Select (MCLR/VPP pin function is MCLR)
#pragma config CP = OFF // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config CPD = OFF // Data Memory Code Protection (Data memory code protection is disabled)
#pragma config BOREN = ON // Brown-out Reset Enable (Brown-out Reset enabled)
#pragma config CLKOUTEN = ON // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)
#pragma config IESO = ON // Internal/External Switchover (Internal/External Switchover mode is enabled)
#pragma config FCMEN = ON // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is enabled)
#pragma config WRT = OFF // Flash Memory Self-Write Protection (Write protection off)
#pragma config PLLEN = OFF // Disabled, see OSCCON
#pragma config STVREN = ON // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset)
#pragma config BORV = LO // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config LVP = OFF // Low-Voltage Programming Enable (Low-voltage programming enabled)
// #pragma config statements should precede project file includes.
#ifndef _i2cSDA
#define _i2cSDA TRISBbits.TRISB4
#endif
#ifndef _i2cCLK
#define _i2cCLK TRISBbits.TRISB6
#endif
#include <xc.h>
#define _XTAL_FREQ 32000000
void init_I2C(void);
unsigned char readI2Cencoder (unsigned char adresaread);
unsigned char yolo=0;
void main(void) {
OSCCON=0b11110000;
_i2cSDA=1u;
_i2cCLK=1u;
TRISCbits.TRISC4=0; //encoder simulator (to be removed)
TRISCbits.TRISC5=0; //encoder simulator (to be removed)
TRISBbits.TRISB7=0; //tester for various bits
ANSELC=0u;
LATCbits.LATC5=0;
LATCbits.LATC4=0;
LATBbits.LATB7=0;
init_I2C();
while(1){
LATCbits.LATC5=0;
LATCbits.LATC4=0;
__delay_ms(50);
LATCbits.LATC5=0;
LATCbits.LATC4=1;
__delay_ms(50);
LATCbits.LATC5=1;
LATCbits.LATC4=1;
__delay_ms(50);
LATCbits.LATC5=1;
LATCbits.LATC4=0;
__delay_ms(50);
yolo=readI2Cencoder(0b10001011);
if ((yolo%5)==0) LATBbits.LATB7=1; //FI ATENT AICI, ca primeste data
else LATBbits.LATB7=0;
}
return;
}
void init_I2C(){
ANSELB=0u;
SSP1STAT=0b00000000; //slew on;
SSP1CON1bits.SSPEN=1; //enable I2C module
SSP1CON1bits.SSPM3=1; //master mode I2C
SSP1CON1bits.SSPM2=0;
SSP1CON1bits.SSPM1=0;
SSP1CON1bits.SSPM0=0;
SSP1CON2bits.GCEN=0; //no general call
/* I2C frecventa = FOSC/((SSPxADD + 1)*4)
pentru 400 000 => 32 000 000 / ((19 + 1)*4) */
SSPADD=19;
return;
}
unsigned char readI2Cencoder(unsigned char adresaread){
unsigned char data_size;
SSP1CON2bits.SEN=1;
while (SSP1CON2bits.SEN); //wait for start seq to finish
PIR1bits.SSP1IF = 0; //reset MSSP interrupt flag (i2c in this case)
SSP1BUF=adresaread; //device address + read
if (SSP1CON1bits.WCOL) goto stop;
while(SSP1STATbits.BF); //wait until write cycle is complete
while ((SSP1CON2 & 0x1F) | (SSP1STATbits.R_nW)); //wait MSSP idle
while(!PIR1bits.SSP1IF);
if(SSP1CON2bits.ACKSTAT) goto stop; //no ack, slave not present
SSP1CON2bits.RCEN = 1; //switch to receive mode
while (!SSP1STATbits.BF); //wait the first byte
if (SSP1CON1bits.SSPOV) goto stop; //receive overflow
data_size = SSP1BUF; //get the data
while ( SSP1CON2bits.RCEN ); //check that receive sequence is over
if (PIR2bits.BCL1IF){PIR2bits.BCL1IF = 0;goto stop;} //return with Bus Collision error, clear the condition
SSP1CON2bits.ACKDT = 1; //set acknowledge bit state for ACK
SSP1CON2bits.ACKEN = 1; //send ACK
while (SSP1CON2bits.ACKEN); //wait ACK sequence to finish
stop:
PIR2bits.BCL1IF=0;
PIR1bits.SSP1IF=0;
SSP1CON2bits.PEN = 1;//initiate stop sequence
while (SSP1CON2bits.PEN);
return data_size;
}
Edited: panic over, all I need it to do is reread the documentation "On the last byte of data communicated, the master device may end the transmission by ending a Stop bit. If the master device is in Receive mode, it sends the Stop bit in place of the last ACK bit. A Stop bit is indicated by a low-to-high transition of the SDAx line while the SCLx line is held high.
In some cases, the master may want to maintain control of the bus and re-initiate another transmission. If so, the master device may send another Start bit in place of the Stop bit or last ACK bit when it is in receive mode."