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.

Tiva C I2C configuration problem

Hi, 

Im trying to have the MPU 6050 IMU sensor interfaced through  I2C communication. My problem is when going through the setup process as outlined in the data sheet, the I2C1_MDR_R register is always zero or always 255. 

Here's my code 


#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_memmap.h"
#include "inc/hw_ints.h"
#include "driverlib/debug.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/pin_map.h"
#include "driverlib/rom.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"
#include "utils/uartstdio.h"
#include "sensorlib/hw_mpu9150.h"
#include "sensorlib/hw_ak8975.h"
#include "sensorlib/i2cm_drv.h"
#include "sensorlib/ak8975.h"
#include "sensorlib/mpu9150.h"
#include "sensorlib/comp_dcm.h"
#include "sensorlib/hw_mpu6050.h"
#include "inc/tm4c123gh6pm.h"


int main(void) {
	
	uint32_t acc_x_L=0;

while(1){

	//16.4.1 Configure the I2C Module to Transmit a Single Byte as a Master
	//The following example shows how to configure the I2C module to transmit a single byte as a master.

	//This assumes the system clock is 20 MHz.

	//1. Enable the I2C clock using the RCGCI2C register in the System Control module (see page 348).
	SYSCTL_RCGCI2C_R=(1<<1);//selected i2c module 1 (will connect to portA pin 6 and 7 with I2C1_SCL and I2C1_SDA respectively

	//2. Enable the clock to the appropriate GPIO module via the RCGCGPIO register in the System
	//Control module (see page 340). To find out which GPIO port to enable, refer to Table
	//23-5 on page 1351.
	SYSCTL_RCGCGPIO_R=(1<<0);//Clock to port A (pin 6 and 7 will have I2C1_SCL and I2C1_SDA respectively)


	//3. In the GPIO module, enable the appropriate pins for their alternate function using the
	//GPIOAFSEL register (see page 671). To determine which GPIOs to configure, see Table
	///23-4 on page 1344.
	GPIO_PORTA_AFSEL_R=0xC0;//pin 6 and 7 are assigned alternative function. Nanmely connecting to I2C1_SCL and I2C1_SDA respectively
	GPIO_PORTA_DEN_R=0b11000000;//set pin 6 and 7 to be digitcal pins
	GPIO_PORTA_PUR_R=0b11000000;//SDA and SCL pulled up


	//4. Enable the I2CSDA pin for open-drain operation. See page 676.
	GPIO_PORTA_ODR_R=0b10000000;//set SDA pin to open drain (bit 7 (pin 8) is set to high)

	//5. Configure the PMCn fields in the GPIOPCTL register to assign the I2C signals to the appropriate
	//pins. See page 688 and Table 23-5 on page 1351.
	GPIO_PORTA_PCTL_R=(0x33 <<24);

	//6. Initialize the I2C Master by writing the I2CMCR register with a value of 0x0000.0010.
	I2C1_MCR_R=0x10;

	//7. Set the desired SCL clock speed of 100 Kbps by writing the I2CMTPR register with the correct
	//value. The value written to the I2CMTPR register represents the number of system clock periods
	//in one SCL clock period. The TPR value is determined by the following equation:
	//TPR = (System Clock/(2*(SCL_LP + SCL_HP)*SCL_CLK))-1;
	//TPR = (16MHz/(2*(6+4)*100000))-1;
	//TPR = 7
	//Write the I2CMTPR register with the value of 0x0000.0007.
	I2C1_MTPR_R=0x9;

	//8. Specify the slave address of the master and that the next operation is a Transmit by writing the
	//I2CMSA register with a value of 0x0000.0076. This sets the slave address to 0x3B.
	I2C1_MSA_R=(0x68 <<1 & 0xFE);// send

	//9. Place data (byte) to be transmitted or recived in the data register by writing the I2CMDR register with the
	//desired data.
	I2C1_MDR_R= 0x3C;//write the register to read from

	//10. Initiate a single byte transmit of the data from Master to Slave by writing the I2CMCS register
	//with a value of 0x0000.0007 (STOP, START, RUN).
	I2C1_MCS_R=0b00000011;

	//11. Wait until the transmission completes by polling the I2CMCS register's BUSBSY bit until it has
	//been cleared.
	while(I2C1_MCS_R & 0b00000001 !=0);



	I2C1_MCS_R=0b00001011;

	// Wait while i2c module is not busy
	//while(!(I2C1_MCS_R & 0b00000001 !=0))

	I2C1_MSA_R=(0x68<<1 | 0x01);// recieve


	//12. Check the ERROR bit in the I2CMCS register to confirm the transmit was acknowledged.
	while (I2C1_MCS_R & 0x02 != 0);
}

	return 0;
}

Mind you I am forced to code everything in registers so I cant code anything using the pre defined libraries. 

Your help will be appreciated,

  • Hello Saeed

    Why are your forced to code in DRM and not use TivaWare. Please note that DRM may be deprecated on TivaWare, so eventually you have to move to TivaWare. Why not now and help yourself and us to debug the issue?

    Regards
    Amit
  • Hi Amit,

    I'm working on a personal project so I want to work in low level programming (using registers). It's also helping me learn i2c better .

    I just have one simple goal of observing change (reading) in the i2c MDR register , thats it for now.

    Can you check to see if my start, run, stop sequence is correct . All I'm doing in this code is sending slave address of 0x68 ( selecting mpu 6050) next i select which register to read from (0x3C) then finally I bring the slave into read mode .

    Some of the comments don't reflect What I have written in the code as the code was updated. I will send you more clear code soon.

  • Hello Saeed,

    We were discussing this earlier on the forum (in the following forum post)

    e2e.ti.com/.../496927

    DRM IS NOT AN EFFECTIVE LEARNING TOOL AS ERROR PROBABILITY IS HIGHER.

    As you may see that almost all examples in TivaWare are built from TivaWare library and there are reference code on I2C Master in TivaWare, that will allow both of us to quickly debug a code.

    Regards
    Amit
  • In that case, here's my attempt at using TivaWare APIs:

    #include <stdint.h>
    #include <stdbool.h>
    //#include "Tiva_i2c.h"
    #include "inc/tm4c123gh6pm.h"
    #include "inc/hw_i2c.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_types.h"
    #include "inc/hw_gpio.h"
    #include "driverlib/i2c.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/gpio.h"
    #include "driverlib/pin_map.h"
    #include "sensorlib/hw_mpu6050.h"
    
    
    /*void writeI2C1(uint16_t device_address, uint16_t device_register, uint8_t device_data);
    void initI2C1(void);
    uint8_t readI2C1(uint16_t device_address, uint16_t device_register);*/
    
    
    
    void initI2C1(void)
    {
    //This function is for eewiki and is to be updated to handle any port
    
    //enable I2C module
    SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C1);
    
    //reset I2C module
    SysCtlPeripheralReset(SYSCTL_PERIPH_I2C1);
    
    //enable GPIO peripheral that contains I2C
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    
    // Configure the pin muxing for I2C1 functions on port A6 and A7.
    GPIOPinConfigure(GPIO_PA6_I2C1SCL);
    GPIOPinConfigure(GPIO_PA7_I2C1SDA);
    
    // Select the I2C function for these pins.
    GPIOPinTypeI2CSCL(GPIO_PORTA_BASE, GPIO_PIN_6);
    GPIOPinTypeI2C(GPIO_PORTA_BASE, GPIO_PIN_7);
    
    // Enable and initialize the I2C1 master module. Use the system clock for
    // the I2C1 module. The last parameter sets the I2C data transfer rate.
    // If false the data rate is set to 100kbps and if true the data rate will
    // be set to 400kbps.
    I2CMasterInitExpClk(I2C1_BASE, SysCtlClockGet(), false);
    
    //clear I2C FIFOs
    HWREG(I2C1_BASE + I2C_O_FIFOCTL) = 80008000;
    }
    
    uint8_t readI2C1(uint16_t device_address, uint16_t device_register)
    {
    //specify that we want to communicate to device address with an intended write to bus
    I2CMasterSlaveAddrSet(I2C1_BASE, device_address, false);
    
    //the register to be read
    I2CMasterDataPut(I2C1_BASE, device_register);
    
    //send control byte and register address byte to slave device
    I2CMasterControl(I2C1_BASE, I2C_MASTER_CMD_SINGLE_SEND);
    
    //wait for MCU to complete send transaction
    while(I2CMasterBusy(I2C1_BASE));
    
    //read from the specified slave device
    I2CMasterSlaveAddrSet(I2C1_BASE, device_address, true);
    
    //send control byte and read from the register from the MCU
    I2CMasterControl(I2C1_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE);
    
    //wait while checking for MCU to complete the transaction
    while(I2CMasterBusy(I2C1_BASE));
    
    //Get the data from the MCU register and return to caller
    return( I2CMasterDataGet(I2C1_BASE));
    }
    
    void writeI2C1(uint16_t device_address, uint16_t device_register, uint8_t device_data)
    {
    //specify that we want to communicate to device address with an intended write to bus
    I2CMasterSlaveAddrSet(I2C1_BASE, device_address, false);
    
    //register to be read
    I2CMasterDataPut(I2C1_BASE, device_register);
    
    //send control byte and register address byte to slave device
    I2CMasterControl(I2C1_BASE, I2C_MASTER_CMD_BURST_SEND_START);
    
    //wait for MCU to finish transaction
    while(I2CMasterBusy(I2C1_BASE));
    
    I2CMasterSlaveAddrSet(I2C1_BASE, device_address, true);
    
    //specify data to be written to the above mentioned device_register
    I2CMasterDataPut(I2C1_BASE, device_data);
    
    //wait while checking for MCU to complete the transaction
    I2CMasterControl(I2C1_BASE, I2C_MASTER_CMD_BURST_RECEIVE_FINISH);
    
    //wait for MCU & device to complete transaction
    while(I2CMasterBusy(I2C1_BASE));
    }
    
    
    int main(void) {
    
    SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN |SYSCTL_XTAL_16MHZ);
    
    uint8_t gyroY_H=0;
    
    initI2C1();//initilize the I2c
    writeI2C1(MPU6050_WHO_AM_I_MPU6050, MPU6050_O_PWR_MGMT_1, 0x00);//configure sleep mode off
    gyroY_H=readI2C1(MPU6050_WHO_AM_I_MPU6050, MPU6050_O_GYRO_XOUT_H);//output the data
    
    
    
    return 0;
    }



    I ran into the same issue while using the API'. However, I had an additional issue of having the exit.c file popping up when I tried to debug the program. I can still run the program, however  I need click on the Resume button twice in order to run the program. 

    Overall, I still seem to read value of 0 at my MDR Register of I2c1.

    Update:I dont know why but putting an while loop in main program prevents the exit.c file from popping up after after I resume in debug mode. 

  • Saeed Molaie said:
    ...required to work in low level programming (using registers). It's also helping me learn i2c better .

    Feel your pain - I do - yet unexplained (and curious) is, "How you're learning I2C better?"    

    You're stuck - are you not - and wash ashore here desperately seeking help.   And - making matters worse - you've spent hours of time/effort (endlessly) viewing multiple, arcane MCU registers - really, "What have you learned?"   And - how much will you remember?  (guaranteed - in a week/10 days max - your learning will have dissipated)   Not so w/the API - each time you employ a function its usage & application will become more apparent - especially so as it works.   That's (real) learning - is it not?

    This problem is not yours - nor your school's alone.   In today's world the race is to the swift - not to those rejecting more efficient and error-free methods.  (i.e. vendor's superb API)

    If your teacher/professor ran a small tech business - I'd wager a good sum that he/she would NOT employ DRM - or would do so minimally.   (assumes the goal is to make - not lose - money...)

    Nothing prevents you from (starting) w/the API - getting your code to run/work - and (only then) investigating the sequencing & manipulations of arcane registers...

  • Hello Saeed

    Thank you. I very much appreciate the transition.

    1. TM4C123x does not have the FIFOCTL register. So the following line is not required
    HWREG(I2C1_BASE + I2C_O_FIFOCTL) = 80008000;

    2. In the writeI2C1 function, why is the direction of the transaction being changed to read?

    //wait for MCU to finish transaction
    while(I2CMasterBusy(I2C1_BASE));

    I2CMasterSlaveAddrSet(I2C1_BASE, device_address, true);

    3. In the readI2C1 function, I see a Write transaction with Stop condition followed by a read transaction. Normally devices do support that but what i seen more commonly is that there is a write of Register Address, followed by a repeated start.

    //send control byte and register address byte to slave device
    I2CMasterControl(I2C1_BASE, I2C_MASTER_CMD_BURST_SEND_START);

    //wait for MCU to complete send transaction
    while(I2CMasterBusy(I2C1_BASE));

    //read from the specified slave device
    I2CMasterSlaveAddrSet(I2C1_BASE, device_address, true);

    //send control byte and read from the register from the MCU
    I2CMasterControl(I2C1_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE);

    Regards,
    Amit
  • I made all the changes you have recommended but I still have no result from MDR register (displays either 0 or 255).

    Also, I observed that  I still encounter the exit.c pop up when I debug, if I don't have any while loop in my main code.

    I also tried to apply this code to a pressure sensor      (MPL 3115A2) while changing the configuration process to that recommended by sensor data sheet  but still no results.

  • Hello Saeed,

    You need to put a while(1); at the end of the main function for preventing it to go to exit.c. I hope the correct Slave Address is being sent to the Slave device. You can check this with a scope/LA, if the for the Slave Address, the slave device sends an ACK.

    Regards
    Amit
  • #include <stdint.h>
    #include <stdbool.h>
    //#include "Tiva_i2c.h"
    #include "inc/tm4c123gh6pm.h"
    #include "inc/hw_i2c.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_types.h"
    #include "inc/hw_gpio.h"
    #include "driverlib/i2c.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/gpio.h"
    #include "driverlib/pin_map.h"
    #include "sensorlib/hw_mpu6050.h"
    #include "driverlib/rom.h"
    
    
    
    /*void writeI2C3(uint16_t device_address, uint16_t device_register, uint8_t device_data);
    void initI2C3(void);
    uint8_t readI2C3(uint16_t device_address, uint16_t device_register);*/
    
    
    
    void initI2C3(void)
    {
    	//This function is for eewiki and is to be updated to handle any port
    
    	//enable I2C module
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C3);
    
    	//reset I2C module
    	//SysCtlPeripheralReset(SYSCTL_PERIPH_I2C3);
    
    	//enable GPIO peripheral that contains I2C
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
    
    	// Configure the pin muxing for I2C3 functions on port A6 and A7.
    	 GPIOPinTypeI2CSCL(GPIO_PORTD_BASE, GPIO_PIN_0);
    	 GPIOPinTypeI2C(GPIO_PORTD_BASE, GPIO_PIN_1);
    
    	// Select the I2C function for these pins.
    	GPIOPinTypeI2CSCL(GPIO_PORTD_BASE, GPIO_PIN_0);
    	GPIOPinTypeI2C(GPIO_PORTD_BASE, GPIO_PIN_1);
    
    	// Enable and initialize the I2C3 master module.  Use the system clock for
    	// the I2C3 module.  The last parameter sets the I2C data transfer rate.
    	// If false the data rate is set to 100kbps and if true the data rate will
    	// be set to 400kbps.
    	I2CMasterInitExpClk(I2C3_BASE, SysCtlClockGet(), false);
    
    
    }
    
    uint8_t readI2C3(uint16_t device_address, uint16_t device_register)
    {
    	//specify that we want to communicate to device address with an intended write to bus
    	I2CMasterSlaveAddrSet(I2C3_BASE, device_address, false);
    
    	//the register to be read
    	I2CMasterDataPut(I2C3_BASE, device_register);
    
    	//send control byte and register address byte to slave device
    	I2CMasterControl(I2C3_BASE, I2C_MASTER_CMD_BURST_SEND_START);
    
    	//wait for MCU to complete send transaction
    	while(I2CMasterBusy(I2C3_BASE));
    
    	//read from the specified slave device
    	I2CMasterSlaveAddrSet(I2C3_BASE, device_address, true);
    
    	//send control byte and read from the register from the MCU
    	I2CMasterControl(I2C3_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE);
    
    	//wait while checking for MCU to complete the transaction
    	while(I2CMasterBusy(I2C3_BASE));
    
    	//Get the data from the MCU register and return to caller
    	return( I2CMasterDataGet(I2C3_BASE));
    }
    
    void writeI2C3(uint16_t device_address, uint16_t device_register, uint8_t device_data)
    {
    	//specify that we want to communicate to device address with an intended write to bus
    	I2CMasterSlaveAddrSet(I2C3_BASE, device_address, false);
    
    	//register to be read
    	I2CMasterDataPut(I2C3_BASE, device_register);
    
    	//send control byte and register address byte to slave device
    	I2CMasterControl(I2C3_BASE, I2C_MASTER_CMD_BURST_SEND_START);
    
    	//wait for MCU to finish transaction
    	while(I2CMasterBusy(I2C3_BASE));
    
    
    	//I2CMasterSlaveAddrSet(I2C3_BASE, device_address, true);
    
    	//specify data to be written to the above mentioned device_register
    	I2CMasterDataPut(I2C3_BASE, device_data);
    
    	//wait while checking for MCU to complete the transaction
    	I2CMasterControl(I2C3_BASE, I2C_MASTER_CMD_BURST_RECEIVE_FINISH);
    
    	//wait for MCU & device to complete transaction
    	while(I2CMasterBusy(I2C3_BASE));
    }
    
    
    int main(void) {
    
    	SysCtlClockSet(SYSCTL_SYSDIV_5 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ |
    	                       SYSCTL_OSC_MAIN);
    
    	uint8_t OUT_P_MSB=0;
    	uint8_t STA=0;
    
    	initI2C3();//initilize the I2c
    	writeI2C3(0x0C, 0x26, 0xB8);///* Set to Altimeter with an OSR = 128 */
    	writeI2C3(0x0C, 0x13, 0x07);///* Enable Data Flags in PT_DATA_CFG */
    	writeI2C3(0x0C, 0x26, 0xB9);///* Set Active */
    	while(1){
    
    	while((STA=readI2C3(0x0C,0X00)) & 0x08==true)
    	{
    		OUT_P_MSB=readI2C3(0x0C, 0x01);//output the data
    
    	}
    	}
    
    	return 0;
    }

    I am confident that the register address and the slave dresses are correct but I  still cant read anything from MDR register.When I step into the program I observe the code gets stuck at the busy while loop wait when it enters the write and read functions. 

  • Hello Saeed

    Are the Pull Up's installed on the SCL and SDA lines and can you confirm that before the first write and read is performed both SCL and SDA are at High Level (Logic High-3.3V)?

    Also RULE101 of debug: no assumption, would be a good idea to hook up LA or a Scope and see what happens on the bus.

    Regards
    Amit
  • Hi Amit,

    I am not too sure if this is what you were looking for, but I commented the write and read out from the code and then debugged. According to my digital multi-meter, the SCL is 3.3 but the SDA reads 358mV.

    Also, I have no external pull up as the sparkfun MPL 3115A2 break out sensor has internal pull-ups embedded into the board. 

    At the moment I dont have scop/LA so it will be a while before I obtain one.

  • And also when add the lines :

    	// Configure the pin muxing for I2C3 functions on port A6 and A7.
    	GPIOPinConfigure(GPIO_PD0_I2C3SCL);
    	GPIOPinConfigure(GPIO_PD1_I2C3SDA);

    The voltage measured at bith SDA and SCL becomes 1.7V (This voltage is measured when Read and Write is executed). If the Read and Write is not executed the voltage at SDA and SCL is 3.3V given if I add those two additional lines of code.

    I still get stuck in the busy wait and thus get 255 as my MDR read value. 

  • Hi Amit/Saeed,

    Might there be (competition) for "Debug, Rule 101?"   How about NOT starting w/an extremely complex device - and praying/hoping that, "All goes well?"

    That's what's been done - has it not?

    KISS - yes KISS - directs that new users (start) w/simplest, most direct method - and gradually, systematically - build/prove their understanding.

    A far simpler EEPROM proves a powerful learning tool.   Pity that's (bypassed) - both by poster's school & (always) by officialdom, here. 

  • Hello Saeed,

    So under Idle Bus condition, the pull ups are working as expected. The two lines of code are required as part of IO Configuration.

    The only reason why I see that during an I2C read the Busy loop remains, is that

    (a) The Slave device is driving SCL Low as part of Clock Stretching
    (b) It has already NAK'ed the address and the code has an issue because of which it is forcing the controller in Busy state.

    A scope shall be a useful resource.

    Regards
    Amit
  • Hi Amit/c1_mobile,

    I have purchased my own bench mixed signal oscilloscope and it should arrive soon. I will update you guys further  when it arrives.

    In the mean time, I have purchased some EEPROM (Microchip 24LC256) as c1_mobile suggested and configured the I2C using the same code as I posted. Here's an slightly updated version for the EEPROM:

    //EEPROM (MicroChip 24LC256)
    //slave address is A0
    
    #include <stdint.h>
    #include <stdbool.h>
    #include "inc/tm4c123gh6pm.h"
    #include "inc/hw_i2c.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_types.h"
    #include "inc/hw_gpio.h"
    #include "driverlib/i2c.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/gpio.h"
    #include "driverlib/pin_map.h"
    #include "sensorlib/hw_mpu6050.h"
    #include "driverlib/rom.h"
    
    
    
    
    
    void initI2C3(void)
    {
    	//This function is for eewiki and is to be updated to handle any port
    
    	//enable I2C module
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C3);
    
    	//reset I2C module
    	//SysCtlPeripheralReset(SYSCTL_PERIPH_I2C3);
    
    	//enable GPIO peripheral that contains I2C
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
    
    	// Configure the pin muxing for I2C3 functions on port A6 and A7.
    	GPIOPinConfigure(GPIO_PD0_I2C3SCL);
    	GPIOPinConfigure(GPIO_PD1_I2C3SDA);
    
    	// Select the I2C function for these pins.
    	GPIOPinTypeI2CSCL(GPIO_PORTD_BASE, GPIO_PIN_0);
    	GPIOPinTypeI2C(GPIO_PORTD_BASE, GPIO_PIN_1);
    
    	// Enable and initialize the I2C3 master module.  Use the system clock for
    	// the I2C3 module.  The last parameter sets the I2C data transfer rate.
    	// If false the data rate is set to 100kbps and if true the data rate will
    	// be set to 400kbps.
    	I2CMasterInitExpClk(I2C3_BASE, SysCtlClockGet(), false);
    
    
    
    }
    
    uint8_t readI2C3(uint16_t device_address, uint16_t device_register)
    {
    	//specify that we want to communicate to device address with an intended write to bus
    	I2CMasterSlaveAddrSet(I2C3_BASE, device_address, false);
    
    	//the register to be read
    	I2CMasterDataPut(I2C3_BASE, device_register);
    
    	//send control byte and register address byte to slave device
    	I2CMasterControl(I2C3_BASE, I2C_MASTER_CMD_BURST_SEND_START);
    
    	//wait for MCU to complete send transaction
    	while ( I2CMasterBusy(I2C3_BASE));
    
    	//read from the specified slave device
    	I2CMasterSlaveAddrSet(I2C3_BASE, device_address, true);
    
    	//send control byte and read from the register from the MCU
    	I2CMasterControl(I2C3_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE);
    
    	//wait while checking for MCU to complete the transaction
    	while ( I2CMasterBusy(I2C3_BASE) );
    
    	//Get the data from the MCU register and return to caller
    	return( I2CMasterDataGet(I2C3_BASE));
    }
    
    void writeI2C3(uint16_t device_address, uint16_t device_register, uint8_t device_data)
    {
    	//specify that we want to communicate to device address with an intended write to bus
    	I2CMasterSlaveAddrSet(I2C3_BASE, device_address, false);
    
    	//register to be read
    	I2CMasterDataPut(I2C3_BASE, device_register);
    
    	//send control byte and register address byte to slave device
    	I2CMasterControl(I2C3_BASE, I2C_MASTER_CMD_BURST_SEND_START);
    
    	//wait for MCU to finish transaction
    	while ( I2CMasterBusy(I2C3_BASE)  );
    
    
    	//I2CMasterSlaveAddrSet(I2C3_BASE, device_address, true);
    
    	//specify data to be written to the above mentioned device_register
    	I2CMasterDataPut(I2C3_BASE, device_data);
    
    	//wait while checking for MCU to complete the transaction
    	I2CMasterControl(I2C3_BASE, I2C_MASTER_CMD_BURST_RECEIVE_FINISH);
    
    	//wait for MCU & device to complete transaction
    	while ( I2CMasterBusy(I2C3_BASE) );
    }
    
    
    int main(void) {
    
    	SysCtlClockSet(SYSCTL_SYSDIV_5 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ |SYSCTL_OSC_MAIN);
    
    	uint8_t OUT_P_MSB=0;
    
    
    	initI2C3();//initilize the I2c
    	writeI2C3(0xA0, 0x10, 0x07);//* device address, memory location, data*/
    	OUT_P_MSB=readI2C3(0xA0, 0x10);//device address, memory location//
    	while(1);
    
    
    	return 0;
    }
    

    This time I saw the code being able to pass the while busy loop after I installed some 4.7K pull-ups, for each clock and data, but I still see nothing at the MDR register. I connected the chip as the pictures shows:

     

  • Hi Amit,

    Can a forum helper more (like) his poster?   That scope will spectacularly aid - glad you were able to acquire.

    And I'm (greatly) pleased that you accepted the suggestion to acquire (vastly) simpler component.    Again - "One small step for mankind posters!"

    That said - that EEProm is "not" the simplest - and (has itself) issues w/complexity.   (i.e. it has a w-i-d-e address requirement, my direction was (or should have been, "smallest, simplest EEProm" [i.e. one w/256 bytes (max) of address] such makes the I2C addressing much, much easier.

    Always - when bringing up a new system or sub-system - "Think Simplicity."

    Amit/I note your focus upon the MDR Register.   Yet that's "not" KISS!   Instead - as you've acquired & have installed the EEProm - why not write to several addresses - and then "read back?"    Your goal is to successfully transact w/the device.   MDR Register mastery must prove "second to that."   And - once you've successfully "transacted" - then is the best (& proper) time to "read MDR." 

    There should be "PC-based" (free) programs which enable you to "seed" the EEProm with a small amount of data.   This (eliminates) the requirement for you to (successfully) write to the EEProm (that's done via that PC program).   This qualifies as 'KISS" as your only challenge (now) is to "read" from the EEProm.

    Does this make sense to you?   (firm staff nod their approval - [note: they do that too - when we're sailing - and (all) aquatic life "heads to deeper water" to escape cb1's, "imprecise course-setting.]    

  • Some quick thoughts:

    1. The device address here (0xa0) should be shifted to the right by 1 when sending it to API function since the function expects 7 bit address. Send 0xa0>>1 = 0x50 instead. For aesthetic reasons change device_address to type uint8_t instead of uint16_t.

    2. The eeprom chip has no registers but direct memory access by addressing. The memory address is 16 bit wide high byte-low byte order. Your code doesn't send 16 bit wide memory addresses neither in write nor in read functions.
  • Data and clock.rar

    I sent you the scope data for the SDA and SCL pin of pressure sensor. I am a rookie in using the scope so let me know you guys need better screenshot.

    Thanks for your help,

  • Thank you - appreciated - may I suggest scope's "User Guide" and "Operating Manual" as priority read.

    Also - you should be able to force the scope into "Single Shot" capture/storage mode - triggered by the I2C "Start Condition." Then choose one of the "compressed data storage file formats" (.jpg, .png, .tif, etc.).

    The .rar format you've provided is not too popular - neither my firm nor (most) clients employ it on a regular basis.

    ".Zip" or the 3 others I noted here are far more popular & attractive for (most) U.S. based users...   Might you investigate your scope's "storage mode" and choose one of the 3 indicated - thank you.

  • Hello Saeed,

    To be able to use the scope correctly, adjust the time base so that an entire I2C frame can be captured on the display. As cb1 said, change it to Trigger mode: and with SDA falling edge to trigger the scope. So that way when you capture the waveform we see the I2C transaction address and data phase. Also please label the images, or provide a lookup as to what each image is corresponding to in the code.

    Regards
    Amit
  • Hi guys, 

    I attempted to screenshot a whole frame using regular scope and logic analyzer: I2C bus.zip

    For the scope: CH2 (Blue) is the SDA. CH1 (Yellow) is the SCL.  

    For LA: D0 (red) is the SDA. D1: (green) is the SCL. 

    This signal corresponds to the pressure sensor code I posted on Mar 13, 2016 2:24 AM

  • I think I now realize what you need. I will run the code for each section (1. Sending slave address 2. writing data 3... etc.) and scope the code at each of those section. I will also label the code snippet corresponding to the image.

  • Hello Saeed

    I checked the waveform that you sent and it is clear that the Slave device is presenting a NAK during address phase. The address being sent to the Slave device is 0x0C.

    Regards
    Amit
  • Hi Amit,

    You were right about the slave address being wrong. I think you mentioned that in the beginning of this thread but I naively brushed it off. I can Finally read the MDR register!

    My mistake was all along with the slave address (7 bit addressing). I was not aware of the fact that the API function for I2C automatically shifts the slave address to left and adds the read and write bit automatically. Knowing all this, now I can venture into programming in registers.

    I also made a mistake into thinking the WHO_AM_I register listed in the slave data sheet is same as the slave address.

    Thank you all for your help,
  • Hello Saeed,

    I have seen this Slave Address Issue a lot of times on the forum and that is why the I2C application note was created to explain the addressing method w.r.t device data sheet and TM4C12x uC. I should have pointed the forum post to the App Note as well. Insisting on a scope plot was required to cross verify the hypothesis on the issue.

    Glad you are now operational, with your project.

    Regards,
    Amit
  • Dear Amit,
    How to address and write bits into data registers of an i2c slave device?

    Regards,
    Keyshav
  • Hello Keyshav,

    Did you reference the I2C Application Note and the Datasheet I2C Chapter? If yes, then this information is provided explicitly in flowcharts and initialization sequences.