This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

i2c read

Other Parts Discussed in Thread: MSP430F5438A, BQ27200

my master is msp430f5438a and slave device address is 0x55. I am reading the registers of slave device. I am getting correct values from registers 0X00 upto 0x0F. But when i am reading registers with 0X10 and above, RXBUF is reading zero. What might be the problem and how to solve it. The problem i have noticed for registers above 0x10 is that the  NACK Flag is getting set immediately after the restart condition. But this problem is not occurring while reading registers below 0x0F.

  • Mahesh,

    1. What is your slave device?
    2. How do you know it works up to 0x10?
    3. Can you write then read the same value from slave registers?

    Regards,
    Maciej 

  • my slave device is fuel gauge bq27200. the slave address is 0x55. I am reading correct values for registers below 0x10. The problem i have noticed is NACK is getting set after restart condition set for registers above 0x10.

    For example for registers 0x08 and 0x09, i am reading voltage and on board voltage is also almost same. So i said i am reading correct values for registers below 0x10.

  • This is part of my code

    UCB2CTL1 |= UCTR + UCTXSTT;
    while (!(UCB2IFG & UCTXIFG));
    UCB2TXBUF = reg_addr;

    UCB2CTL1 &= ~UCTR;
    UCB2CTL1 |= UCTXSTT; //Send start condition.

    while ((UCB2CTL1) & UCTXSTT); 
    while (!(UCB2IFG & UCRXIFG));
    received_byte = UCB2RXBUF;


    UCB2CTL1 |= UCTXSTP; //Send stop condition to receive just one byte

    while (UCB2CTL1 & UCTXSTP); //Wait for STOP to finish
    return received_byte;

  • Please use code blocks when posting code.

    There is a section of datasheet for I2C communication Communicating with the bq27200 (I2C interface) (http://www.ti.com/lit/ds/symlink/bq27200.pdf)

    You are getting NACK after sending register number? Are you sure you are sending read bit? Can you read-write EEPROM?

    Regards,
    Maciej 

  • Yes i am getting NACK set to 1 after sending register number into TXBUF. Later it get cleared once we transmit the restart condition and RXIFG is set. But my RXBUF is reading zero at this point. Once i transmit the stop condition that time the RXBUF gets updated.  Is this correct? . Why is the code behaving differently for different registers? Because for example register 0x09, once we sent the restart bit, the RXBUF gives correct value. This value i am reading. But again once i transmit the stop bit, the RXBUF Value changes.

  • Mahesh,

    I think at this point it would be a good idea to dump some I2C bus data with oscilloscope and post it here. Then hope that some TIer will be able to asses if this looks good or not.

    I do not think this is an initialization issue but I never worked with this particular chip.

    Regards,
    Maciej 

  • Your code starts with setting UCTXSTT. At this point, UCTXIFG is immediately set (sicn eoyu have UCTR set). SO the while loop is superfluous.
    Now you write the register value to TXBUF. Where it sits until the start byte is actually sent. But you immediately proceed and send a stop. So the register value is never sent, the USCI will immediately send a stop after the start byte is sent.

    After writing the register value to TXBUF and before clearign UCTR and doiing the repeated start, you'll have to wait until the start byte has actually sent.
    Loop until TXSTT clears, then check for NACKIFG, and if it is clear at this point, you can proceed. If it is set, the slave didn't answer and you should issue a stop - or retrywith a repeated start.

    Note that you can't simply wait for TXIFG ofter you wrote the register address to TXBUF. If the slave doesn't ACK, no further TXIFG will come, but instead NACIFG will appear.

  • Hi Jens,

    i have made some changes according to your suggestion

      UCB2CTL1 |= UCTR + UCTXSTT;
     //
         
           	UCB2TXBUF = reg_addr;	//Send single byte data.
    __delay_cycles(30);
          while(UCB2CTL1 & UCTXSTT);
    if((UCB2IFG & UCNACKIFG )==0X20)
    exit();
    else
    {
           	UCB2CTL1 &= ~UCTR;
           	UCB2CTL1 |= UCTXSTT;	//Send start condition.
    
           	while ((UCB2CTL1) & UCTXSTT);	//Poll for Start bit to complete
          while (!(UCB2IFG & UCRXIFG));
             	received_byte = UCB2RXBUF;
    
    
         UCB2CTL1 |= UCTXSTP;	//Send stop condition to receive just one byte
    
    
    
           	while (UCB2CTL1 & UCTXSTP);	//Wait for STOP to finish
           return received_byte;
    }

    Again this code is working fine with some registers. But for some registers the NACKIFG is getting set immediately after we transfer the register address and RXBUF is showing zeros . How to resolve this issue?

  • mahesh sasanur said:
    __delay_cycles(30);

    This line is superfluous

    mahesh sasanur said:
    exit();

    Before exit, you should set UCTXSTP, or the bus remains busy.

    After waiting for UCTXSTT in the RX part, you don't check for NACKIFG again. You should. It's not likely, but it might be that the slave won't answer here.

    Before clearing UCTR (or rather before setting UCTXSTT a second time), you should wait for UCTXIFG being set, to ensure that sending of the register address has actually started. UCTYSTT being clear means teh start byte has been sent and an ACK was received. If you now set UCTXSTT too fast again, the data byte you wrote to TXBUF hasn't started sending and will be discarded.

    mahesh sasanur said:
    NACKIFG is getting set immediately after we transfer the register address and RXBUF is showing zeros

    If you got a NACK (whcih you can only get in the TX part of the code, as you don'T check for NACK in the RX part), then neither the register address was sent, nor did you receive anything. So obviously, RXBUF will show zeroes.

    Are you sure your reg_addr parameter is correct?

  • Hello,

    I am using pic32mx597f512l as a master device and bq27200 as a slave device. I want the code to read the voltage.

    Thanks 

  • Beter Brwon said:

    Hello,

    I am using pic32mx597f512l as a master device and bq27200 as a slave device. I want the code to read the voltage.

    Thanks 

    Hi,

    You should not hijack threads like that. There are sites where you can hire someone to do a work for you. I think https://www.elance.com is a good example.

    Regards,
    Maciej 

  • ok but I want to modify the bq27200 to receive ack properly

    Master Code

    /********************************************************
     * I2C_Master.c: Master code for I2C communication.	*
     * 	Both PICS use I2C1 module to send/ receive data.*
     *	The master sends different values to a slave,   *
     *	which uses an interrupt to respond accordingly.	*
     *							*
     * Hardware: 2 PIC32MX460F512L PICs on NU32 boards	*
     ********************************************************
     * Thomas Peterson, James Rein, Eric West		*
     * ME333 Winter 2010					*
     * File Created: 	05-FEB-2010			*
     * Last Modified: 	14-FEB-2010			*
     *******************************************************/
    
    #include "HardwareProfile.h"
    #include <plib.h>
    
    #define SYSCLK	(80000000)
    #define PBCLK  (SYSCLK)
    #pragma config FPBDIV = DIV_1				//Sets PBCLK to SYSCLK
    
    #define Fsck	50000
    #define BRG_VAL 	((PBCLK/2/Fsck)-2)
     
    #define Nop() asm( "nop" )                 //No-operation; asm stands for assembly, using an assembly command in C.  Cool!
    
    #define INPUT_A9       PORTAbits.RA9
    #define INPUT_A10       PORTAbits.RA10
    
    
    //function declaration for sending data and selecting slave address
    void SendData(int,unsigned int);
    void Delayms( unsigned t);
    
    /*
    This function is a delay function, causing the program to wait for approximately 4 * cnt cycles
    1 cycle is 1/SYSCLK seconds.
    */
    void i2c_wait(unsigned int cnt)
    {
    	while(--cnt)
    	{
    		Nop();
    		Nop();
    	}
    }
    
    
    /* Main function */
    int main(void)
    {
        // Configure the proper PB frequency and the number of wait states.
    	SYSTEMConfigPerformance(SYS_FREQ);
    
    	// Set all analog pins to be digital I/O
       	AD1PCFG = 0xFFFF;
    
    	//Setup TRIS bits for switches and I2C pins
    	TRISAbits.TRISA14=0;
    	TRISAbits.TRISA15=0;
    
    	//Initialize all of the LED pins
    	mInitAllLEDs();
           mInitAllSwitches()
    
    	unsigned char SlaveAddress;   //Slave address variable to tell the master where to send the data.  
                                         //Will be re-assigned for multiple slaves.
    
    	//Enable I2C channel and set the baud rate to BRG_VAL)
    	OpenI2C1( I2C_EN, BRG_VAL );
    
    	int rcv;			//For received data
    
    	//While loop to test LED functionality 
    	while(1) {
    		if (swProgram) {				//First button pressed
    			while(swProgram) { Nop(); }	//Wait for release
    			mLED_2_Toggle();			//Toggle LED2
    			SendData(0xAA,0x40);  			//Sends hex data 0xAA to slave address 0x40
    			rcv = RcvData(0x40);			//Receives data from address 0x40				
    			Delayms(100);
    		}
    		if (swUser) {				//Second button pressed
    			while(swUser) { Nop(); }
    			mLED_1_Toggle();			//Toggle LED1
    			SendData(0x23,0x40);    		//Sends hex data 0xAA to slave address 0x40
    			rcv = RcvData(0x40);		        //Receives data from address 0x40			
    			Delayms(100);		
    		}
    	}//while loop ending
    
    	return 0;
    }  //ending main 
    
    
    /*****************************************************
     * RcvData(unsigned int address)		     *
     *					  	     *
     * Gets a byte of data from I2C slave device at      *
     *  ADDRESS.					     *
     *						     *
     * Returns: Received data			     *
     ****************************************************/
    int RcvData(unsigned int address) {
    	StartI2C1();				//Send line start condition
    	IdleI2C1();			        //Wait to complete
    	MasterWriteI2C1((address << 1) | 1);	//Write out slave address OR 1 (read command)
    	IdleI2C1();				//Wait to complete
    	int rcv = MasterReadI2C1();		//Read in a value
    	StopI2C1();				//Send line stop condition
    	IdleI2C1();				//Wait co complete
    	return rcv;				//Return read value
    }
    
    
    
    /***************************************************
     * SendData(int data, unsigned int address)        *
     *						    *
     * Sends a byte of data (DATA) over the I2C line   *
     *	to I2C address ADDRESS			    *
     *						    *
     * Returns: nothing				    *
     ***************************************************/
    void SendData (int data, unsigned int address){
    	StartI2C1();	        //Send the Start Bit
    	IdleI2C1();		//Wait to complete
    
    	MasterWriteI2C1((address << 1) | 0);  //Sends the slave address over the I2C line.  This must happen first so the 
                                                 //proper slave is selected to receive data.
    	IdleI2C1();	        //Wait to complete
    
    	MasterWriteI2C1(data);  //Sends data byte over I2C line
    	IdleI2C1();		//Wait to complete
    
    	StopI2C1();	        //Send the Stop condition
    	IdleI2C1();	        //Wait to complete
    
    } //end function
    
    
    
    void Delayms( unsigned t)
    // This uses Timer 1, can be changed to another timer. Assumes FPB = SYS_FREQ
    {
        OpenTimer1(T1_ON | T1_PS_1_256, 0xFFFF);
        while (t--)
        {  // t x 1ms loop
            WriteTimer1(0);
            while (ReadTimer1() < SYS_FREQ/256/1000);
    	}
    	CloseTimer1();
    } // Delayms
    

    Slave Code

    /***********************************************************************
     * PIC32 I2C Slave Code                
     ***********************************************************************/
    
    #include "GenericTypeDefs.h"
    #include "Compiler.h"
    #include "HardwareProfile.h"
    #include <plib.h>
    
    #define SYSCLK	(80000000)
    #define PBCLK  (SYSCLK)
    
    #define Fsck	50000
    #define BRG_VAL 	((PBCLK/2/Fsck)-2)
    
    // this is the modules Slave Address
    #define SLAVE_ADDRESS 0x40
    
    // volatile variables to hold the switch and led states
    volatile unsigned char dataRead = 0;
    
    ///////////////////////////////////////////////////////////////////
    //
    //	InitI2C
    //
    // 	Perform initialisation of the I2C module to operate as a slave
    //
    ///////////////////////////////////////////////////////////////////
    void InitI2C(void)
    {
    	unsigned char temp;
    	
    	// Enable the I2C module with clock stretching enabled
    	OpenI2C1(I2C_ON | I2C_7BIT_ADD | I2C_STR_EN, BRG_VAL);
    	
    	// set the address of the slave module, address matching is with bits
    	// 7:1 of the message compared with bits 6:0 of the ADD SFR so we
    	// need to shift the desired address 1 bit. 
    	I2C1ADD = SLAVE_ADDRESS; // >> 1;
    	I2C1MSK = 0;
    	
    	// configure the interrupt priority for the I2C peripheral
    	mI2C1SetIntPriority(I2C_INT_PRI_3 | I2C_INT_SLAVE);
    
    	// clear pending interrupts and enable I2C interrupts
    	mI2C1SClearIntFlag();
    	EnableIntSI2C1;
    }
    
    ///////////////////////////////////////////////////////////////////
    //
    //	main routine
    // 
    //	This code example demonstrates using the PIC32 as an I2C slave
    //	
    //
    ///////////////////////////////////////////////////////////////////
    int main (void)
    {
    	// set for 80MHz operation
    	SYSTEMConfigPerformance(SYSCLK);
    	// set the Pbus to be 40000000
    	mOSCSetPBDIV(OSC_PB_DIV_2);
    	// disable the JTAG port
    	mJTAGPortEnable(0);
    	// enable interrupts
    	INTEnableSystemMultiVectoredInt();
    	
    	InitI2C();
    	mInitAllLEDs();
    
    	// main loop
    	while (1) {
    		/* If global variable "dataRead" is set high during interrupt, turn on all LEDs */
    		if (dataRead == 0xAA)
    		{
    			mLED_0_On();
    			mLED_1_On();
    			mLED_2_On();			
    			mLED_3_On();			
    			
    		}
    	}
    }
    
    ///////////////////////////////////////////////////////////////////
    //
    // Slave I2C interrupt handler
    // This handler is called when a qualifying I2C events occurs
    // this means that as well as Slave events 
    // Master and Bus Collision events will also trigger this handler.
    //
    ///////////////////////////////////////////////////////////////////
    void __ISR(_I2C_1_VECTOR, ipl3) _SlaveI2CHandler(void)
    {
    	mLED_1_On();
    	unsigned char temp;
    	static unsigned int dIndex;
    	
    	// check for MASTER and Bus events and respond accordingly
    	if (IFS0bits.I2C1MIF == 1) {
    		mI2C1MClearIntFlag();
    		return;		
    	}
    	if (IFS0bits.I2C1BIF == 1) {
    		mI2C1BClearIntFlag();
    		return;
    	}
    	mLED_1_Off();
    	mLED_2_On();
    	
    	// handle the incoming message
    	if ((I2C1STATbits.R_W == 0) && (I2C1STATbits.D_A == 0)) {
    		// R/W bit = 0 --> indicates data transfer is input to slave
    		// D/A bit = 0 --> indicates last byte was address  
    		
    		// reset any state variables needed by a message sequence	
    		// perform a dummy read of the address
    		temp = SlaveReadI2C1();
    		
    		mLED_3_On();
    		mLED_2_Off();
    		// release the clock to restart I2C
    		I2C1CONbits.SCLREL = 1; // release the clock
    
    	} else if ((I2C1STATbits.R_W == 0) && (I2C1STATbits.D_A == 1)) {
    		// R/W bit = 0 --> indicates data transfer is input to slave
    		// D/A bit = 1 --> indicates last byte was data
    		
    		mLED_3_On();
    		mLED_2_On();
    		// writing data to our module, just store it in adcSample
    		dataRead = SlaveReadI2C1();
    		
    		// release the clock to restart I2C
    		I2C1CONbits.SCLREL = 1; // release clock stretch bit
    
    	} else if ((I2C1STATbits.R_W == 1) && (I2C1STATbits.D_A == 0)) {
    		// R/W bit = 1 --> indicates data transfer is output from slave
    		// D/A bit = 0 --> indicates last byte was address
    		mLED_0_On();
    		mLED_2_Off();
    		// read of the slave device, read the address 
    		temp = SlaveReadI2C1();
    		dIndex = 0;
    		SlaveWriteI2C1(dataRead);
    	} else if ((I2C1STATbits.R_W == 1) && (I2C1STATbits.D_A == 1)) {
    		// R/W bit = 1 --> indicates data transfer is output from slave
    		// D/A bit = 1 --> indicates last byte was data
    		mLED_0_On();
    		mLED_2_On();
    		
    		// output the data until the MASTER terminates the
    		// transfer with a NACK, continuing reads return 0
    		if (dIndex == 0) {
    			SlaveWriteI2C1(dataRead);
    			dIndex++;
    		} else
    			SlaveWriteI2C1(0);
    	}
    	
    	// finally clear the slave interrupt flag
    	mI2C1SClearIntFlag();		
    }

**Attention** This is a public forum