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.

EK-TM4C123GXL: Problem with I2C busy-bit

Part Number: EK-TM4C123GXL

Tool/software:

I'm a beginner with embedded programming and facing problem while connecting two EK-TM4C123GXL boards via I2C to blink the LED. Two boards are connected on I2C0 pins and initialization was done. To confirm the send transection from the master board, code is checking the status of busy bit (while loop code line 98). On debugging, I've found that busy bit never goes to 0 and hence code is stuck in an infinite while loop. Can anyone please help?

Master Code -

#include "TM4C123.h"                    // Device header
#include <stdio.h>


void I2C_Init(void);
void I2C0_Send(uint8_t slave_addr, char data);
void PORTF_Init(void);
void delay(void);
char I2C0_Recieve(uint8_t slave_addr);

#define RCGCI2C (((volatile unsigned long)(0x400FE000+0x620)))
#define RCGCGPIO (((volatile unsigned long)(0x400FE000+0x608)))
	
//PB2->SCL AND PB3->SDA
#define PORTB_BASE  0x40005000
#define PORTB_AFSEL_R  (((volatile unsigned long) (PORTB_BASE + 0x420)))
#define PORTB_PCTL_R   (((volatile unsigned long) (PORTB_BASE + 0x52C)))
#define PORTB_DIR_R    (((volatile unsigned long) (PORTB_BASE + 0x400)))
#define PORTB_DEN_R    (((volatile unsigned long) (PORTB_BASE + 0x51C)))
#define PORTB_DATA_R   (((volatile unsigned long) (PORTB_BASE + 0x3FC)))
#define PORTB_AMSEL_R  (((volatile unsigned long) (PORTB_BASE + 0x528)))
#define PORTB_ODR_R    (((volatile unsigned long) (PORTB_BASE + 0x50C)))


#define I2C0_BASE      (0x40020000)
#define I2C_MSA_R      (((volatile unsigned long) (I2C0_BASE + 0x00)))
#define I2C_MCS_R_R     (((volatile unsigned long) (I2C0_BASE + 0x004)))
#define  I2C_MCS_W_R    (((volatile unsigned long) (I2C0_BASE + 0x004)))
#define I2C_MDR_R        (((volatile unsigned long) (I2C0_BASE + 0x008)))
#define I2C_MTPR_R       (((volatile unsigned long) (I2C0_BASE + 0x00C)))
#define I2C_MCR_R       (((volatile unsigned long) (I2C0_BASE + 0x020)))
#define I2C_MBMON_R       (((volatile unsigned long) (I2C0_BASE + 0x02C)))

//#define I2C_SOAR_R       (((volatile unsigned long) (I2C0_BASE + 0x00C)))
#define PORTF_BASE    0x40025000
#define PORTF_DIR_R   (((volatile unsigned long) (PORTF_BASE + 0x400)))
#define PORTF_DEN_R   (((volatile unsigned long) (PORTF_BASE + 0x51C)))
#define PORTF_DATA_R  (((volatile unsigned long) (PORTF_BASE + 0x3FC)))
#define PORTF_AFSEL_R (((volatile unsigned long) (PORTF_BASE + 0x420)))
#define PORTF_PCTL_R  (((volatile unsigned long) (PORTF_BASE + 0x52C)))
#define PORTF_AMSEL_R (((volatile unsigned long) (PORTF_BASE + 0x528)))


int main(){
char arr[3]={'G','B','G'};
I2C_Init();
PORTF_Init();
uint8_t ad=0x2C;
int i=0;
while(1){
	
      I2C0_Send(ad,arr[i]);
     char data=I2C0_Recieve(ad);
        if (data == 'R') {
            PORTF_DATA_R = 0x02; // Red LED on PF1
        } else if (data == 'G') {
            PORTF_DATA_R = 0x08; // Green LED on PF3
        } else if (data == 'B') {
            PORTF_DATA_R = 0x04; // Blue LED on PF2
        }
        i =i+1;
				if(i==3)
					i=0;
        delay();
}

} 

void I2C_Init(void){
  RCGCI2C|=0x01;
  RCGCGPIO|=0x02;

	PORTB_AFSEL_R|=0x0C;
	PORTB_ODR_R|=0x08;//open drain for data line
	PORTB_DEN_R|=0x0C;
	PORTB_PCTL_R|=0x3300;
	PORTB_AMSEL_R&=~0x0C;
	I2C_MCR_R=0x10;
	I2C_MTPR_R=7;//SET CLOCK 100KBPS
}
void PORTF_Init(void) {
    RCGCGPIO |= 0x20; // enable GPIO Port F clock
    PORTF_DIR_R = 0x0E; // PF1, PF2, and PF3 as output (LEDs)
    PORTF_DEN_R |= 0x0E; // digital enable PF1, PF2, and PF3
    PORTF_AFSEL_R &=~0x0E; // disable alternate function
    PORTF_PCTL_R &=~0xFFF0; // configure as GPIO
    PORTF_AMSEL_R &= ~0x0E; // disable analog function
	  
}

void I2C0_Send(uint8_t  slave_addr,  char data) {
	  while(I2C_MCS_R_R&0x01){};//wait unitt i2c0 is busy
    I2C_MSA_R = (slave_addr<<1)&0xFE;			// Set slave address 
			I2C_MSA_R&=~0x01;//specify a write operation
    I2C_MDR_R = data&0xFF; 
    I2C_MCS_W_R = 0x07; // Start, Run, and Stop conditions

    while (I2C_MCS_R_R& 0x01==1) {}; // Wait for the transmission to complete
		// I2C_MCS_R_R&(0x0D);
}

char I2C0_Recieve(uint8_t slave_addr){
    while(I2C_MCS_R_R&0x01){};//wait unitt i2c0 is busy
		 I2C_MSA_R = (slave_addr<<1)&0xFE;			// Set slave address 
			I2C_MSA_R|=0x01;//specify a read operation
		I2C_MCS_W_R = 0x07; // Start, Run, and Stop conditions
		while (I2C_MCS_R_R& 0x01) {};//busy bit
		return (char)I2C_MDR_R & (0xFF);
}

void delay(void) {
    unsigned long i = 8000000;
    while (i > 0) {
        i--;
    }
}

Slave Code -

#include "TM4C123.h"                    // Device header
#include <stdio.h>


void I2C_Init(void);
void slave_Send(char data);
void PORTF_Init(void);
void delay(void);
char slave_Recieve(void);

#define RCGCI2C (((volatile unsigned long)(0x400FE000+0x620)))
#define RCGCGPIO (((volatile unsigned long)(0x400FE000+0x608)))
	
//PB2->SCL AND PB3->SDA
#define PORTB_BASE  0x40005000
#define PORTB_AFSEL_R  (((volatile unsigned long) (PORTB_BASE + 0x420)))
#define PORTB_PCTL_R   (((volatile unsigned long) (PORTB_BASE + 0x52C)))
#define PORTB_DIR_R    (((volatile unsigned long) (PORTB_BASE + 0x400)))
#define PORTB_DEN_R    (((volatile unsigned long) (PORTB_BASE + 0x51C)))
#define PORTB_DATA_R   (((volatile unsigned long) (PORTB_BASE + 0x3FC)))
#define PORTB_AMSEL_R  (((volatile unsigned long) (PORTB_BASE + 0x528)))
#define PORTB_ODR_R    (((volatile unsigned long) (PORTB_BASE + 0x50C)))


#define I2C0_BASE      (0x40020000)
#define I2C_SOAR_R      (((volatile unsigned long) (I2C0_BASE + 0x800)))
#define I2C_SCS_R_R     (((volatile unsigned long) (I2C0_BASE + 0x804)))
#define  I2C_SCS_W_R    (((volatile unsigned long) (I2C0_BASE + 0x804)))
#define I2C_SDR_R        (((volatile unsigned long) (I2C0_BASE + 0x808)))
#define I2C_MCR_R       (((volatile unsigned long) (I2C0_BASE + 0x020)))
	
#define PORTF_BASE    0x40025000
#define PORTF_DIR_R   (((volatile unsigned long) (PORTF_BASE + 0x400)))
#define PORTF_DEN_R   (((volatile unsigned long) (PORTF_BASE + 0x51C)))
#define PORTF_DATA_R  (((volatile unsigned long) (PORTF_BASE + 0x3FC)))
#define PORTF_AFSEL_R (((volatile unsigned long) (PORTF_BASE + 0x420)))
#define PORTF_PCTL_R  (((volatile unsigned long) (PORTF_BASE + 0x52C)))
#define PORTF_AMSEL_R (((volatile unsigned long) (PORTF_BASE + 0x528)))


int main(){
char arr[3]={'G','B','R'};
I2C_Init();
PORTF_Init();
int i=0;
PORTF_DATA_R=0;
while(1){
     
     char data=slave_Recieve();
        if (data == 'R') {
            PORTF_DATA_R = 0x02; // Red LED on PF1
        } else if (data == 'G') {
            PORTF_DATA_R = 0x08; // Green LED on PF3
        } else if (data == 'B') {
            PORTF_DATA_R = 0x04; // Blue LED on PF2
        }
		  slave_Send(arr[i]);
        i =i+1;
				if(i==3)
					i=0;
}

} 

void I2C_Init(void){
   RCGCI2C|=0x01;
   RCGCGPIO|=0x02;

	PORTB_AFSEL_R|=0x0C;
	PORTB_ODR_R|=0x08;
	PORTB_DEN_R|=0x0C;
	PORTB_PCTL_R|=0x3300;
	
	I2C_MCR_R=0x20;//slave mode is on
	I2C_SOAR_R=0x2C;//setting its address
	I2C_SCS_W_R=0x01;//enable slave
}
void PORTF_Init(void) {
    RCGCGPIO |= 0x20; // enable GPIO Port F clock
    PORTF_DIR_R = 0x0E; // PF1, PF2, and PF3 as output (LEDs)
    PORTF_DEN_R |= 0x0E; // digital enable PF1, PF2, and PF3
    PORTF_AFSEL_R &=~0x0E; // disable alternate function
    PORTF_PCTL_R &=~0xFFF0; // configure as GPIO
    PORTF_AMSEL_R &= ~0x0E; // disable analog function
	  
}

void slave_Send( char data) {
	  while(I2C_SCS_R_R&0x02==0){}//wait unittl MASTER IS NOT READY
	  I2C_SDR_R=data;		
}

char slave_Recieve(void){
	while(I2C_SCS_R_R&0x01==0){}//wait while data is not sned
		return (char) I2C_SDR_R&0xFF;
}

void delay(void) {
    unsigned long i = 8000000;
    while (i > 0) {
        i--;
    }
}

  • Hi,

      Three comments I have.

      First, is there a strong reason why you are not using TivaWare SDK?  You are using DRM (Direct Register Manipulation) code. TivaWare SDK contains I2C drivers with APIs that will greatly ease the software developments. There are also examples that you can reference. You can find examples in the below directories. As you can see in FAQ #4, https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/695568/faq-faqs-for-tm4c-arm-cortex-m4f-microcontrollers, we do not support DRM style of coding. If you must use DRM, please at least refer to the TivaWare API source code to see how the registers are configured and initialized. 

    C:\ti\TivaWare_C_Series-2.2.0.295\examples\boards\ek-tm4c123gxl-boostxl-senshub\humidity_sht21_simple

    C:\ti\TivaWare_C_Series-2.2.0.295\examples\peripherals\i2c

      Secondly, when you connect two boards together you must have external pullup resistors (e.g. 4.7kohm) on both the SDA and SCL buses. Without the pullup resistors, they will not work as this is a requirement per I2C protocol. 

      Thirdly, I will strongly suggest you use a logic analyzer or at least a scope to probe the signals. A logic analyzer will easily show you what is put out on the bus and reveal what is not working.