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 interrupts not clearing

Hi everyone,

I'm currently trying to interface with the SHT21 on the SensorHub Boosterpack without using the I2CM libraries, and I'm running into some trouble with the I2C communications. I've included my code below, and at https://gist.github.com/madvoid/9481264 for easy viewing.

// Defines -------------------------------------------------------------------------------------------
#define LED_RED GPIO_PIN_1
#define LED_BLUE GPIO_PIN_2
#define LED_GREEN GPIO_PIN_3

#define SHT21_I2C_ADDRESS  0x40
#define SHT21_TEMP_NOBLOCK 0xE3


// Variables -----------------------------------------------------------------------------------------
static uint32_t g_I2C3Data;			// Data gathered from I2C3 master
static bool g_I2C3DataReceived = false;		// Flag indicating whether data has been received


// Functions -----------------------------------------------------------------------------------------
void ConfigureUART(void){

	// Enable the peripherals used by UART
	ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
	ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);

	// Set GPIO A0 and A1 as UART pins.
	GPIOPinConfigure(GPIO_PA0_U0RX);
	GPIOPinConfigure(GPIO_PA1_U0TX);
	ROM_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);

        // Configure UART clock using UART utils
        UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);
        UARTStdioConfig(0, 115200, 16000000);
}

void ConfigureI2C3(void){
	
	// Enable peripherals used by I2C
	ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
	ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C3);

	// Set GPIO D0 and D1 as SCL and SDA
	ROM_GPIOPinConfigure(GPIO_PD0_I2C3SCL);
	ROM_GPIOPinConfigure(GPIO_PD1_I2C3SDA);

	// Setup SCL and SDA
	ROM_GPIOPinTypeI2CSCL(GPIO_PORTD_BASE, GPIO_PIN_0);
	ROM_GPIOPinTypeI2C(GPIO_PORTD_BASE, GPIO_PIN_1);

	// Initialize as master - Chane 'false' to 'true' if fast mode is desired
	ROM_I2CMasterInitExpClk(I2C3_BASE, ROM_SysCtlClockGet(), false);

	// Enable I2C Interrupts
	ROM_IntEnable(INT_I2C3);
	ROM_I2CMasterIntEnableEx(I2C3_BASE, I2C_MASTER_INT_DATA);

	// Debug
	UARTprintf("I2C3 Setup\n");
}

void I2C3MasterIntHandler(void){

	// Clear interrupt
	ROM_I2CMasterIntClear(I2C3_BASE);

	// Control master?
	ROM_I2CMasterControl(I2C3_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE);

	// Gather data
	g_I2C3Data = ROM_I2CMasterDataGet(I2C3_BASE);

	// Set flag
	g_I2C3DataReceived = true;

	// Print confirmation
	UARTprintf("Interrupt Received\n");
}



// Main ----------------------------------------------------------------------------------------------
int main(void){

	// Enable lazy stacking
	ROM_FPULazyStackingEnable();

	// Set the system clock to run at 40Mhz off PLL with external crystal as reference.
	ROM_SysCtlClockSet(SYSCTL_SYSDIV_5 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ | SYSCTL_OSC_MAIN);

	// Initialize the UART and write status.
	ConfigureUART();
	UARTprintf("SHT21 Example\n");

	// Enable LEDs
	ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
	ROM_GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, LED_RED|LED_BLUE|LED_GREEN);

	// Enable I2C3
	ConfigureI2C3();

	// Insert sleep mode stuff here in the future

	// Enable Interrupts
	ROM_IntMasterEnable();

	// Main loop
	while(1){

		// Set address, put data in buffer, and send
		ROM_I2CMasterSlaveAddrSet(I2C3_BASE, SHT21_I2C_ADDRESS, false);
		ROM_I2CMasterDataPut(I2C3_BASE, SHT21_TEMP_NOBLOCK);
        	ROM_I2CMasterControl(I2C3_BASE, I2C_MASTER_CMD_SINGLE_SEND);


		// Wait until data is received
		while(!g_I2C3DataReceived){
		}

		// Print raw result
		UARTprintf("Raw Result: %i\n",g_I2C3Data);
		g_I2C3DataReceived = false;
		
		// Blink LED
		ROM_GPIOPinWrite(GPIO_PORTF_BASE, LED_RED|LED_GREEN|LED_BLUE, LED_GREEN);
		ROM_SysCtlDelay(ROM_SysCtlClockGet()/3/10);	// Delay for 100ms (1/10s) :: ClockGet()/3 = 1second
		ROM_GPIOPinWrite(GPIO_PORTF_BASE, LED_RED|LED_GREEN|LED_BLUE, 0);

		ROM_SysCtlDelay(ROM_SysCtlClockGet()/3);	// Delay for 1 second
	}
}

When I run this code, the "Interrupt Received" print statement will repeatedly print, and the LED will never blink, which makes me think that the interrupt is not properly cleared or keeps getting called. When I move the data print statement to inside the interrupt handler, the data is printed as zero. Or, am I missing a disable command somewhere?

According to the SHT21 data sheet, the process for getting a raw temp measurement is address write, temp command write, and then after some time a read will be available, which is what I (think) I am doing.

I am using a Tiva Launchpad with arm-none-eabi-gcc, OS X 10.9.2, and I'm programming with the lm4flash programmer.

Any insight will be immensely helpful, and thanks in advance!

  • Hello Nipun,

    I believe the following code in the Interrupt Handler will cause the Interrupt to refire as you request for a new transfer every time the interrupt is asserted for the previous transaction

        // Control master?
        ROM_I2CMasterControl(I2C3_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE);

    Regards

    Amit

  • Hi Amit,

    Thank you for your prompt response! When I remove that line, it no longer executes the interrupt over and over again, but it does not run any code after the interrupt (i.e. I don't see anything after the while(!g_I2C3DataReceived) loop) 

    If I place a print statement within the while(!g_I2C3DataReceived) loop, it usually performs part of of the print statement and then stops, without displaying the print statement within the interrupt function. I can post the updated code if you would like.

    Now it almost seems as if the micro controller is crashing, I just cannot figure out where or why.

  • Hello Nipun,

    So basically the print after the following code never happens?

            // Wait until data is received
            while(!g_I2C3DataReceived){
            }
            // Print raw result
            UARTprintf("Raw Result: %i\n",g_I2C3Data);

    An updated code post would be most useful and indication as to where it gets stuck when viewed through the debugger even better?

    Also it seems you are sending one byte and receiving one byte. Is that correct? If yes, then when doing the read operation you would have to change direction for the Slave using the R/W bit in the I2C Frame using

    ROM_I2CMasterSlaveAddrSet(I2C3_BASE, SHT21_I2C_ADDRESS, true);

    before you read the data from I2CMaster

    Regards

    Amit

  • Hi Amit,

    Thank you for your continued help.

    You are correct, the first print statement after the while(!g_I2C3DataReceived) does not happen. 

    Your comments did make me realize some bugs that I had in my code. First, I had put the SHT21 temperature request code as "Hold Master Mode" instead of "No Hold Master Mode" as I intended. I also added the read operation using I2CMasterSlaveAddrSet() line as you suggested. Finally, I wanted to clarify, I am sending one byte (the temperature request code), and receiving two bytes (the high and low temperature bytes). Unfortunately, these changes did not fix the problem, as the everything after the while loop mentioned above still does not run. I have also not figured out how to use GDB on a Mac, but when I do I will post results. Updated code below:

    // Defines -------------------------------------------------------------------------------------------
    #define LED_RED GPIO_PIN_1
    #define LED_BLUE GPIO_PIN_2
    #define LED_GREEN GPIO_PIN_3
    
    #define SHT21_I2C_ADDRESS  0x40
    #define SHT21_TEMP_NOBLOCK 0xF3
    
    
    // Variables -----------------------------------------------------------------------------------------
    static uint32_t g_I2C3Data1;			// Data bit 1 gathered from I2C3 master
    static bool g_I2C3DataReceived = false;		// Flag indicating whether data has been received
    
    
    // Functions -----------------------------------------------------------------------------------------
    void ConfigureUART(void){
    
    	// Enable the peripherals used by UART
    	ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    	ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
    
    	// Set GPIO A0 and A1 as UART pins.
    	GPIOPinConfigure(GPIO_PA0_U0RX);
    	GPIOPinConfigure(GPIO_PA1_U0TX);
    	ROM_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
    
            // Configure UART clock using UART utils
            UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);
            UARTStdioConfig(0, 115200, 16000000);
    }
    
    void ConfigureI2C3(void){
    	
    	// Enable peripherals used by I2C
    	ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
    	ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C3);
    
    	// Set GPIO D0 and D1 as SCL and SDA
    	ROM_GPIOPinConfigure(GPIO_PD0_I2C3SCL);
    	ROM_GPIOPinConfigure(GPIO_PD1_I2C3SDA);
    
    	// Setup SCL and SDA
    	ROM_GPIOPinTypeI2CSCL(GPIO_PORTD_BASE, GPIO_PIN_0);
    	ROM_GPIOPinTypeI2C(GPIO_PORTD_BASE, GPIO_PIN_1);
    
    	// Initialize as master - Chane 'false' to 'true' if fast mode is desired
    	ROM_I2CMasterInitExpClk(I2C3_BASE, ROM_SysCtlClockGet(), false);
    
    	// Enable I2C Interrupts
    	ROM_IntEnable(INT_I2C3);
    	ROM_I2CMasterIntEnableEx(I2C3_BASE, I2C_MASTER_INT_DATA);
    
    	// Debug
    	UARTprintf("I2C3 Setup\n");
    }
    
    void I2C3MasterIntHandler(void){
    
    	// Clear interrupt
    	ROM_I2CMasterIntClear(I2C3_BASE);
    
    
    	// Gather data
    	g_I2C3Data1 = ROM_I2CMasterDataGet(I2C3_BASE);
    
    	// Set flag
    	g_I2C3DataReceived = true;
    
    	// Print confirmation
    	UARTprintf("Interrupt Received\n");
    }
    
    
    
    // Main ----------------------------------------------------------------------------------------------
    int main(void){
    
    	// Enable lazy stacking
    	ROM_FPULazyStackingEnable();
    
    	// Set the system clock to run at 40Mhz off PLL with external crystal as reference.
    	ROM_SysCtlClockSet(SYSCTL_SYSDIV_5 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ | SYSCTL_OSC_MAIN);
    
    	// Initialize the UART and write status.
    	ConfigureUART();
    	UARTprintf("SHT21 Example\n");
    
    	// Enable LEDs
    	ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
    	ROM_GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, LED_RED|LED_BLUE|LED_GREEN);
    
    	// Enable I2C3
    	ConfigureI2C3();
    
    	// Insert sleep mode stuff here in the future
    
    	// Enable Interrupts
    	ROM_IntMasterEnable();
    
    	// Main loop
    	while(1){
    
    		// Set address, put data in buffer, and send
    		ROM_I2CMasterSlaveAddrSet(I2C3_BASE, SHT21_I2C_ADDRESS, false);
    		ROM_I2CMasterDataPut(I2C3_BASE, SHT21_TEMP_NOBLOCK);
            	ROM_I2CMasterControl(I2C3_BASE, I2C_MASTER_CMD_SINGLE_SEND);
    
    		// Set address
    		ROM_I2CMasterSlaveAddrSet(I2C3_BASE, SHT21_I2C_ADDRESS, true);
    
    		// Wait until data is received
    		while(!g_I2C3DataReceived){
    		}
    
    		// Print raw result
    		UARTprintf("Raw Result 1: %i\n",g_I2C3Data1);
    		g_I2C3DataReceived = false;
    		
    		// Blink LED
    		ROM_GPIOPinWrite(GPIO_PORTF_BASE, LED_RED|LED_GREEN|LED_BLUE, LED_GREEN);
    		ROM_SysCtlDelay(ROM_SysCtlClockGet()/3/10);	// Delay for 100ms (1/10s) :: ClockGet()/3 = 1second
    		ROM_GPIOPinWrite(GPIO_PORTF_BASE, LED_RED|LED_GREEN|LED_BLUE, 0);
    
    		ROM_SysCtlDelay(ROM_SysCtlClockGet()/3);	// Delay for 1 second
    	}
    }

  • Hello Nipun,

    I checked the datasheet for the SMT21 and actually Hold Master mode is much better way of transferring data if there are no other Slaves that need to be communicated with or any other Master on the I2C Bus.

    Also are you able to scope the bus so that it can be used to co-relate with the I2C programming.

    Regards

    Amit

  • Hi Amit,

    Thanks again for checking that for me. I changed a large amount of my program to get rid of interrupts and now I have it working. (I'll post the code below)

    However, I am currently using the No Hold Master mode, and I may switch to the Hold Master mode if it proves to be better. Can you explain a little more about what you mean when you say "scope the bus so that it can be used to co-relate with the I2C"?

    Thank you,
    Nipun

    Code below:

    // Defines -------------------------------------------------------------------------------------------
    #define LED_RED GPIO_PIN_1
    #define LED_BLUE GPIO_PIN_2
    #define LED_GREEN GPIO_PIN_3
    
    #define SHT21_I2C_ADDRESS  0x40
    #define SHT21_TEMP_NOBLOCK 0xF3
    
    
    // Variables -----------------------------------------------------------------------------------------
    static uint32_t g_I2C3Data[3];			// Data byte gathered from I2C3 master
    
    
    // Functions -----------------------------------------------------------------------------------------
    void ConfigureUART(void){
    
    	// Enable the peripherals used by UART
    	ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    	ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
    
    	// Set GPIO A0 and A1 as UART pins.
    	GPIOPinConfigure(GPIO_PA0_U0RX);
    	GPIOPinConfigure(GPIO_PA1_U0TX);
    	ROM_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
    
            // Configure UART clock using UART utils
            UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);
            UARTStdioConfig(0, 115200, 16000000);
    }
    
    void ConfigureI2C3(void){
    	
    	// Enable peripherals used by I2C
    	ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
    	ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C3);
    
    	// Setup GPIO
    	ROM_GPIOPinTypeI2CSCL(GPIO_PORTD_BASE, GPIO_PIN_0);
    	ROM_GPIOPinTypeI2C(GPIO_PORTD_BASE, GPIO_PIN_1);
    
    	// Set GPIO D0 and D1 as SCL and SDA
    	ROM_GPIOPinConfigure(GPIO_PD0_I2C3SCL);
    	ROM_GPIOPinConfigure(GPIO_PD1_I2C3SDA);
    
    	// Initialize as master - Change 'false' to 'true' if fast mode is desired
    	ROM_I2CMasterInitExpClk(I2C3_BASE, ROM_SysCtlClockGet(), false);
    
    	// Debug
    	UARTprintf("I2C3 Setup\n");
    }
    
    void FloatToPrint(float floatValue, uint32_t splitValue[2]){
    	int32_t i32IntegerPart;
    	int32_t i32FractionPart;
    
            i32IntegerPart = (int32_t) floatValue;
            i32FractionPart = (int32_t) (floatValue * 1000.0f);
            i32FractionPart = i32FractionPart - (i32IntegerPart * 1000);
            if(i32FractionPart < 0)
            {
                i32FractionPart *= -1;
            }
    
    	splitValue[0] = i32IntegerPart;
    	splitValue[1] = i32FractionPart;
    }
    
    
    
    // Main ----------------------------------------------------------------------------------------------
    int main(void){
    
    	// Enable lazy stacking
    	ROM_FPULazyStackingEnable();
    
    	// Set the system clock to run at 40Mhz off PLL with external crystal as reference.
    	ROM_SysCtlClockSet(SYSCTL_SYSDIV_5 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ | SYSCTL_OSC_MAIN);
    
    	// Initialize the UART and write status.
    	ConfigureUART();
    	UARTprintf("SHT21 Example\n");
    
    	// Enable LEDs
    	ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
    	ROM_GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, LED_RED|LED_BLUE|LED_GREEN);
    
    	// Enable I2C3
    	ConfigureI2C3();
    
    	// Set address, put data in buffer, and send
    	ROM_I2CMasterSlaveAddrSet(I2C3_BASE, SHT21_I2C_ADDRESS, false);
    	ROM_I2CMasterDataPut(I2C3_BASE, SHT21_TEMP_NOBLOCK);
    	ROM_I2CMasterControl(I2C3_BASE, I2C_MASTER_CMD_SINGLE_SEND);
    	UARTprintf("Data Sent\n");
    	
    	// Wait for transfer finish
    	while(ROM_I2CMasterBusy(I2C3_BASE)){}
    
    	// Delay - Wait for measurement to complete
    	ROM_SysCtlDelay(ROM_SysCtlClockGet()/3*2);
    
    	// Set address to read
    	ROM_I2CMasterSlaveAddrSet(I2C3_BASE, SHT21_I2C_ADDRESS, true);
    	
    	// Master read data byte 1 and store	
    	ROM_I2CMasterControl(I2C3_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE);
    	while(ROM_I2CMasterBusy(I2C3_BASE)){}
    	g_I2C3Data[0] = ROM_I2CMasterDataGet(I2C3_BASE);
    
    	// Master read data byte 2 and store
    	ROM_I2CMasterControl(I2C3_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE);
    	while(ROM_I2CMasterBusy(I2C3_BASE)){}
    	g_I2C3Data[1] = ROM_I2CMasterDataGet(I2C3_BASE);
    
    	// Master read data byte 3 (checksum) and store
    	ROM_I2CMasterControl(I2C3_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE);
    	while(ROM_I2CMasterBusy(I2C3_BASE)){}
    	g_I2C3Data[2] = ROM_I2CMasterDataGet(I2C3_BASE);
    
    	// Print results
    	UARTprintf("Data Byte 1: %x\n",g_I2C3Data[0]);
    	UARTprintf("Data Byte 2: %x\n",g_I2C3Data[1]);
    	UARTprintf("Data Byte 3: %x\n",g_I2C3Data[2]);
    
    	// Convert to temperature
    	uint32_t printTemp[2];
    	uint16_t tempConvert = ((uint16_t)g_I2C3Data[0] << 8) | (uint16_t)(g_I2C3Data[1]);
    	UARTprintf("TempConvert: %x\n",tempConvert);
    	float temp = (float)(tempConvert & 0xFFFC);
    	temp = -46.85f + 175.72f * (temp/65536.0f);
    	FloatToPrint(temp,printTemp);
    
    	// Print temperature
    	UARTprintf("Temperature: %d.%03d\n",printTemp[0],printTemp[1]);
    	
    	// Blink LED
    	ROM_GPIOPinWrite(GPIO_PORTF_BASE, LED_RED|LED_GREEN|LED_BLUE, LED_GREEN);
    	ROM_SysCtlDelay(ROM_SysCtlClockGet()/3/10);	// Delay for 100ms (1/10s) :: ClockGet()/3 = 1second
    	ROM_GPIOPinWrite(GPIO_PORTF_BASE, LED_RED|LED_GREEN|LED_BLUE, 0);
    
    	return 0;
    }

  • Hello Nipun,

    I meant connecting a scope or a Logic Analyser on the I2C SCL and SDA Pins.

    Good to hear it is working now.

    Regards

    Amit Ashara

  • Ah, I see. Amit, thanks for all your help, I'm going to mark this as solved.

    - NG