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-Master Problem; strange behavior

Hello,

I have some problem to bring the I2C-Master to work.

My setup:
TivaLaunchpad (I2C-Master)
custom Board with MSP430Gx-Controller (I2C-Slave)
Debugging in CCS with full licence
I2C-pullup with around 4kOhm i think
I2c-clock at 100Kb/s

Below is the program. I will give a short description. The I2C-Master should send the address and 3 data bytes. When i run the program like it is i get the following picture at my oscilloscope:

Here you can see that the address will be sent out and the ACK is set correctly. But the next and only byte is the last one with 0x55. This should be the third byte. The data bytes one and two are missing. Why do this happen? I can´t explain that.

But i tried some more things and all things i have done confused me more and more. Here my other tries with pictures.

Try 1: 
- set a breakpoint to the command data put (it´s the second byte)
- program run into the breakpoint and as you can see the address and the first data byte is sent out correctly

- let the program move on

- this is the second data byte and it looks fine
- after this the program will stick in the while loop for waiting of the clearance of the busy byte forever; just a reset helps

Try 2:
- add a 5000 cycle delay between first data byte and second data byte

- without a breakpoint this will stick in the busy-loop forever

Can anyone give me an explanation of that behavior? I think i have tried almost anything but haven´t found a solution. The slave works fine and make all acknowledges he should do. The program never runs into the error interrupt of the I2c.

#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/sysctl.h"
#include "driverlib/gpio.h"
#include "driverlib/i2c.h"
#include "driverlib/interrupt.h"

uint8_t SLAVE_ADDRESS = 0x0F;

uint32_t first_byte, second_byte, temperature, result;

static volatile int iCtr=0;
void iicInt(){
	iCtr++;
}

void i2c_setup(void) {

	//SysCtlClockSet(SYSCTL_SYSDIV_4|SYSCTL_USE_PLL|SYSCTL_XTAL_16MHZ|SYSCTL_OSC_MAIN);

	//Enable the I2C Module
	SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C2);

	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);

	//Wait at least 5 clock cycles
	SysCtlDelay(2);

	//Configure SDA and SCL
	GPIOPinConfigure(0x00041003);

	GPIOPinConfigure(0x00041403);

	//Wait at least 5 clock cycles
	SysCtlDelay(2);

	//Set PE4 as SCL
	GPIOPinTypeI2CSCL(GPIO_PORTE_BASE, GPIO_PIN_4);

	//Set PE5 as SDA
	GPIOPinTypeI2C(GPIO_PORTE_BASE, GPIO_PIN_5);

	//Configure Master,
	I2CMasterInitExpClk(I2C2_BASE, SysCtlClockGet(), false);

	// interrupt
	I2CIntRegister(I2C2_BASE, iicInt);

}

typedef struct {
	unsigned char all;
	union{
		unsigned char r1	:1;
		unsigned char r2	:1;
		unsigned char r3	:1;
		unsigned char r4	:1;
		unsigned char r5	:1;
		unsigned char r6	:1;
		unsigned char r7	:1;
		unsigned char r8	:1;
	}single;
}rel_t;
uint32_t i2c_read() {
	volatile rel_t iRelPos;
	iRelPos.all = 0x55;

	// address + dlc + crc
	I2CMasterSlaveAddrSet(I2C2_BASE, SLAVE_ADDRESS, false);

	I2CMasterDataPut(I2C2_BASE, 0x01);

	I2CMasterControl(I2C2_BASE, I2C_MASTER_CMD_BURST_SEND_START);

	while(I2CMasterBusBusy(I2C2_BASE)); //Loop until the bus is no longer busy


	//SysCtlDelay(5000);

	// command
	I2CMasterDataPut(I2C2_BASE, 0x07);

	I2CMasterControl(I2C2_BASE, I2C_MASTER_CMD_BURST_SEND_CONT);

	while(I2CMasterBusBusy(I2C2_BASE)); //Loop until the bus is no longer busy

	//SysCtlDelay(2000);

	// state
	I2CMasterDataPut(I2C2_BASE, iRelPos.all);

	I2CMasterControl(I2C2_BASE, I2C_MASTER_CMD_BURST_SEND_FINISH);

	while(I2CMasterBusBusy(I2C2_BASE)); //Loop until the bus is no longer busy

	/*
	I2CMasterSlaveAddrSet(I2C2_BASE, SLAVE_ADDRESS, true );

	I2CMasterControl(I2C2_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE);

	while(I2CMasterBusBusy(I2C2_BASE)); //Loop until the bus is no longer busy

	first_byte = I2CMasterDataGet(I2C2_BASE);
	*/

	return first_byte;

}

void setup()
{
	i2c_setup();
}

void main()
{
	setup();
	while(1)
	{
		int test = i2c_read();
		SysCtlDelay(5000);
	}
}
  • Michael Wiesent said:
    //Configure SDA and SCL GPIOPinConfigure(0x00041003); GPIOPinConfigure(0x00041403);

    The defines for that are at pin_map.h

    #define GPIO_PE4_I2C2SCL        0x00041003

    #define GPIO_PE5_I2C2SDA        0x00041403

    Also, I noticed at your interrupt handler iicInt, you did not clear interrupt flag.

    - kel

  • That´s just a optical correction. 

    Now I added the clearing of the interrupt flag at the interrupt call. But that is not the problem because the interrupt will never be called.

  • Hi Michael,

         There are lots of post in the forum regarding I2C. See, if TI Amit's advices in those post might help you. Here are some below.

        TIVA: Send 1 byte via I2C and receive 2 bytes

        I2C master read on TIVA TM4CDNCPDT

        Tiva tm4c123 launchpad I2C transmission

    - kel  

  • While there are, "lots of posts dealing w/I2C" (i.e. "Go Hunt") I see this: (note: we use LX4F as master, multiple I2C slaves)

    while(I2CMasterBusBusy()

    Our code is near identical to yours - yet runs/works - and we use  "while(I2CMasterBusy()"  instead of BusBusy!

    I'm unsure if both of your MCUs must operate & exchange in, "Master-Master" mode.  If that's not the case - may be worthwhile to , "KILL that Bus!"

  • That´s the solution. This three letters cost me several hours of my lifetime. 

    Thank you for this information. Now the signals are as expected.

  • Michael Wiesent said:
    These three letters cost me several hours of my lifetime. 

    Feel your pain - glad to have assisted - thanks for your Verify.

    You are not alone in such encounters.  May I suggest - as a general, "method of attack" - that when (and they will) a particular function call fails you then survey the Peripheral Driver Library (and maybe even the source .c file) seeking, "near alternative functions." 

    You were so close - yet devil lurks in such fine details.  (and - we doubt - you'll make that miscue anytime again...)

  • I want to echo cb1's sentiment here... there's a lot of posts regarding i2c on the forum and they all seem to be attempting to discover how to do the most basic things.

    Does someone want to put together a library of useful functions on top of Tivaware? Each should have a demo app to show how it is used. Obviously, most won't do anything if you have no i2c devices on the bus.

    1. Master Mode-Send an address, check ACK or NAK
    2. Master Mode-Send an address (handle ACK), then read a byte and send the ACK
    3. Master Mode-Send an address (handle ACK), send a byte (handle ACK)
    4. Master Mode-Send an address (handle ACK), send a byte (handle ACK), read a byte (and do ACK)
    5. Slave Mode-see any address on the bus, ACK just my address
    6. Slave Mode-see just my address when it is sent, ACK it
    7. Slave Mode-respond to my address by sending a byte, see if it is ACKed
    8. Slave Mode-respond to my address by receiving a byte, then on some condition either ACK or NAK (e.g. if bit 1 is set or something)
    9. Slave Mode-respond to my address by receiving a byte and sending a byte back, see if it is ACKed

    Those nine would answer almost all the questions I've seen. Add a well-written introduction that covers pull-ups and what to look for with a scope, and make versions of those 9 for all of:

    1. No interrupts, no DMA
    2. Interrupt-driven, no DMA
    3. No interrupts, use DMA
    4. Interrupt-drive, use DMA

    Then make that a sticky.

    If nobody else feels up to it, I'll do it.