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.

Stellaris LaunchPad : Unable to alter I2C Data Register (I2CMDR)

Hi All!

I have been attempting to interface my Stellaris Launchpad with a  sparkfun BMP180 pressure/temperature sensor break out and I have hit a snag.

The necessary's all all ok (Voltage levels etc) and i have tested the breakout with a picKit Uno32 and it's working fine.

I would really like to use the Stellaris LP for the project so I started small and am attempting to read a single byte from the BMP180 via I2C.

I have read the LM4F's I2C documentation with regards to this and I saw that there is a very useful step by step guide to sending a single byte as a master around the page 971 mark.

The issue is that I cannot seem to alter the data in some of the relevant registers for I2C comms

them being the data (MDR) reg and the control (MCS) reg.

I would be very grateful if someone could throw in here !

see the following code :


#include "stdio.h"
#include "inc/hw_types.h"
#include "inc/hw_memmap.h"
#include "driverlib/sysctl.h"
#include "driverlib/adc.h"
#include "driverlib/pin_map.h"
#include "driverlib/hibernate.h"
#include "driverlib/gpio.h"
#include "driverlib/uart.h"
#include "driverlib/systick.h"
#include "utils/uartstdio.h"
#include "driverlib/rom.h"
#include "driverlib/interrupt.h"
#include "driverlib/fpu.h"
#include "driverlib/i2c.h"
#include "inc/hw_ints.h"
#include "utils/ustdlib.h"
#include "string.h"
#include "stdint.h"

// Chip Header .. declares I2C3_MASTER_MCS_R etc.
#include "lm4f120h5qr.h"



/*
	---Definitions
*/

#define PRES_SENSOR_ADDR 0x77 // 7-bit address
#define SEND_ADDR ((PRES_SENSOR_ADDR <<1)& 0xFE) 
#define RECV_ADDR ((PRES_SENSOR_ADDR <<1)| 0x01)
//i.e. 7 addr bits and a zero for R/S bit

#define MASTER_BUSY (1u)
#define MASTER_ERR (1u<<1)
#define READ_BYTES_ERR 0x01



int main(void) {
	
		
		

		//Set up sys clk
		ROM_SysCtlClockSet(SYSCTL_SYSDIV_1 |SYSCTL_USE_OSC | SYSCTL_OSC_MAIN |SYSCTL_XTAL_16MHZ);

		SysCtlDelay(10000);
	
		//Clock gate to GPIOD
		SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);

		//Set up i2c Pin types
		GPIOPinTypeI2CSCL(GPIO_PORTD_BASE,GPIO_PIN_0);
		GPIOPinTypeI2C(GPIO_PORTD_BASE,GPIO_PIN_1);

		GPIOPinConfigure(GPIO_PD0_I2C3SCL);
		GPIOPinConfigure(GPIO_PD1_I2C3SDA);

		//Enable the i2c peripheral
		SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C3);

	    I2CMasterInitExpClk(I2C3_MASTER_BASE,SysCtlClockGet(),false);

		SysCtlDelay(10000);

	
		int addr = 0xAA;
		int byteRead =-10;
	
		//set master up for a write
		I2CMasterSlaveAddrSet(I2C3_MASTER_BASE,0x77,false);
	
		//Put data on Data Reg
		I2CMasterDataPut(I2C3_MASTER_BASE,addr);
		/*So we should get 0xAA (170 decimal) on the I2C3 Data 
			register , but I see no chnage
	    */
		
		//Request a single send
		I2CMasterControl(I2C3_MASTER_BASE,I2C_MASTER_CMD_SINGLE_SEND);
		/*
			Again I see no change in the memory listings for the MCS register
		*/
	
	
		//Wait for the Tx to finish
		while(I2C3_MASTER_MCS_R & MASTER_BUSY);
			
	 
	 
		//Set the Master to Read
		I2CMasterSlaveAddrSet(I2C3_MASTER_BASE,0x77,true);
	 
		//We are doing a single read
		I2CMasterControl(I2C3_MASTER_BASE,I2C_MASTER_CMD_SINGLE_RECEIVE);

		//Wait for the Rx to finish
	    while(I2C3_MASTER_MCS_R & MASTER_BUSY);
		
	 
			 if(I2C3_MASTER_MCS_R & MASTER_ERR)
			  {
	 			result = (int)READ_BYTES_ERR;
			  }
			 else
			  {
				 byteRead = (int)I2CMasterDataGet(I2C3_MASTER_BASE);
			  }
	 
			while(1);
			return 0;
}

// END OF CODE

When I run this everything compiles fine. Put as commented when I attempt to debug I do not see any changes to the I2C_MDR register after the I2CMasterDataPut() command (Reg stays at 0x00000000). So naturally I am not seeing anything returned form the temp sensor

I have tried the following:

1- Use the direct approach and setup the i2c port and regs directly using solelty the definitions in the lm4f's header file

e.g. 

I2C3_MASTER_MSA_R = SEND_ADDR;
I2C3_MASTER_MDR_R = (addr & 0xFF);
I2C3_MASTER_MCS_R = 0x7;

etc.

2- A different i2c port

So I can only assume I am doing something incredibly silly here ? I can see form GPIODs regs that pull-ups and AFSEL are correct.

All help appreciated !

  • Hello Jason,

    if you have a scope or a LA, can you check if the I2C SCL and SDA lines are "High" and that when you write to the I2CMCS register, does the Master send the Slave Address and the 0xAA byte?

    The Read of I2CMDR register will return the data from the Read Buffer and not what you have written to the I2C module. Since there has been no read done from the Slave the reset value of 0x0 will come if the Read of the MDR register is performed.

    Regards

    Amit

  • I may be a while getting access to a scope but I will try what you have suggested although I don't know if I will be able to see the 0xAA etc on the SDA line ?

    Would I be correct in saying that after Pull Up and AFSEL config has been completed the SDA and SCL lines should be high when the I2C module is idle? Just so I can give you meaningfull feedback here 

    Overall , does the code  look ok to you ?  (i.e. I have not done something silly here ?)

    I tried taking CCS out of the equation incase it was just a memory view issue and I tried the following code in IAR using only bare bones register accesses and I am seeing a similar result!

    #include "lm4f120h5qr.h"
    
    #define PRES_SENSOR_ADDR 0x77 // 7-bit address
    #define SEND_ADDR ((PRES_SENSOR_ADDR <<1)& 0xFE)// 7 bit addr + '0'
    #define RECV_ADDR ((PRES_SENSOR_ADDR <<1)| 0x01)// 7 bit addr + '1'
    #define I2C_SINGLE_SEND    0x00000007
    #define I2C_SINGLE_RECEIVE  0x00000007                                       
    #define MASTER_BUSY (1u)
    #define MASTER_ERR (1u<<1)
    
    
    
    //int readByteMainI2C3(unsigned int addr);
    
    int main()
    {
    	/*
    		Light the Blue LED to ensure successful download
    	*/
    	SYSCTL_RCGCGPIO_R=0x20U; //Enable Clock for GPIOF
    	GPIO_PORTF_DIR_R =0x0EU;// set pins 1,2 and 3 as o/ps
    	GPIO_PORTF_DEN_R =0x0EU;//Dig En
    	GPIO_PORTF_DATA_R=0x04
    	int returnedByte = 0;
    
        //i2c1 Setup
    
    	SYSCTL_RCGCI2C_R |= (1u<<1);//Clock Gate I2C1
    	SYSCTL_RCGCGPIO_R |=(1u);//Clock Gate Gpio Port A
    
    	GPIO_PORTA_AFSEL_R  = 0xC0;// Port A Alternate Pin Function Pin 6 and 7
    	GPIO_PORTA_ODR_R = (1u<<7);//Port A Pin 7 Open Drain
    	GPIO_PORTA_PCTL_R = (0x33 <<24);
                
    	I2C1_MASTER_MCR_R = 0x10;//Master Mode Enabled
    	I2C1_MASTER_MTPR_R = 0x9;//Set Master Timer Period
        
    	/*
    		Send some data
    	*/
    	I2C1_MASTER_MSA_R = SEND_ADDR;
    	I2C1_MASTER_MDR_R = (0xAA);
                 
    	I2C1_MASTER_MCS_R =I2C_SINGLE_SEND;//Set the master control to send a single byte
         
    	//Wait while i2c module is busy
    	while(I2C1_MASTER_MCS_R & MASTER_BUSY);
                
                
    	I2C1_MASTER_MSA_R = RECV_ADDR;
    	I2C1_MASTER_MCS_R =I2C_SINGLE_RECEIVE;
    
        //Wait while i2c module is busy         
    	while(I2C1_MASTER_MCS_R & MASTER_BUSY);
                 
    	if(I2C1_MASTER_MCS_R & MASTER_ERR)
    	{
    		returnedByte = -10;
    	}
    	else
    	{
    		returnedByte = (int)I2C1_MASTER_MDR_R;
    	}
                 
                
                
    	while(1);
    	return 0;
    }
    
    
    
    

    And again I see no change on the MDR reg. I will try to perform the tests you suggested. Thanks for your help here !

  • Hello Jason,

    Thanks for the updated code post. The DEN for Port A Pins 6 and 7 is not set. This has to be set.

    Secondly, I would suggest putting wait for not busy as it takes some time for the I2C controller to begin transmission.

            // Wait while i2c module is not busy
    	while(!(I2C1_MASTER_MCS_R & MASTER_BUSY));
    	//Wait while i2c module is busy
    	while(I2C1_MASTER_MCS_R & MASTER_BUSY);

    CCS would not be the cause as I have used I2C1 with CCS earlier on TM4C123

    Regards

    Amit

  • Hi Amit,

    That did the trick (changing PORTA's DEN) also I noted that the program does not work if I single step , instead I would have to put a breakpoints before and after the whole transaction i.e.

    "BREAKPOINT"

    Master Send Single Byte

    Wait

    Master Receive Single Byte

    Wait

    Check for Error

    "BREAKPOINT"

    Do "something" with data.

    I assume, to the processor the single step approach is far far too slow so things don't work ?

    Also I noted the step - by - step instructions on page 971 (and following page)  of the LM4F's data sheet does not explicitly inform the user that internal pull-ups need to be enabled ( which I unfortunately followed) only ODR.

    Thank you for your help !

  • Hello Jason,

    Yes, when single stepping the external device may timeout (if the slave supports clock low timeout). This would break the I2C communication

    The internal Pull up are weak (13K-30K) which may not be suitable if the line load is higher and would warrant a stronger pull up resistor externally

    Glad it got to working.

    Regards

    Amit