I2C master - slave data
Posted: Mon Oct 30, 2017 8:08 am
Short story: I want to make an encoder(slave). When a master require the data with how many pulses it counted, and interrupt is generated in the slave and data will be transmited via I2C. The problem is (I think the way I constructed the master) specially this SSP1CON2bits.ACKDT = 0; when this is off, the master recive the corect data, do not send the ACK (as seen in fisrt pic), this behavior in intended, the program run without an apparent problem.
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:
Master:
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."
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."