I2C master - slave data

I2C master - slave data

Postby Entropy » 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:

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."
Attachments
2.jpg
2.jpg (121.75 KiB) Viewed 36 times
1.jpg
1.jpg (83.9 KiB) Viewed 36 times
16F1829i2cSlaveInterrupt.c
(3.36 KiB) Downloaded 2 times
16f1829_i2c_master.c
(5.04 KiB) Downloaded 3 times
Entropy
 
Posts: 24
Joined: Fri Sep 04, 2015 7:04 am
Location: Timisoara, Romania

Return to SSP (IIC, SPI)

Who is online

Users browsing this forum: No registered users and 1 guest