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.

TM4C123GH6PMI / I2C and HMC5883L

I am a noob. I am able to get the TM4C123 working with an IO expander but I am getting frustrated trying to get this compass working. With this code, I get back zeros. Is there anyone with some experience with this sensor that can give me a nudge in the right direction. 

I have 4.7K resistors on sda/scl

here is the datasheet: http://www51.honeywell.com/aero/common/documents/myaerospacecatalog-documents/Defense_Brochures-documents/HMC5883L_3-Axis_Digital_Compass_IC.pdf

Thank you !

#include <stdint.h>
#include "PLL.h"

#include "TM4C123GH6PM.h"

uint8_t rc;

  __asm void Delay(unsigned long ulCount)
  {
    subs    r0, #1
    bne     Delay
    bx      lr
  }

	// ************************************************************
	// (1<<0) run
	// (1<<1)	start
	// (1<<2)	stop
	// (1<<3)	ack	
	// ************************************************************
	#define run_start_stop 0x7		
	#define run_start_ack	0xB		
	#define run_ack	0x9		
	#define	run_stop_ack 0xD		
	#define run_start 0x3		
	#define run_stop	0x5		
	
	void setSlaveAddress(uint8_t slaveAddress){
	// ************************************************************
	// setSlaveAddress(uint8_t slaveAddress)
	//
	// MSA = Master Slave Address
	// ************************************************************
		I2C1_MSA_R = (slaveAddress<<1);
	}

	void setRW(uint8_t mode){
	// ************************************************************
	// setRW(uint8_t mode)
	//
	// ************************************************************
		if(mode==0)
		{
			I2C1_MSA_R &= ~(1<<0);	// Writing - Clear the bit
		}else{
			I2C1_MSA_R |= (1<<0);		// Revieving - Set the bit
		}
		
	}
	// ************************************************************
	// checkMCS
	// ************************************************************
	void checkMCS()
	{
		rc = I2C1_MCS_R;
		if((rc & (1<<1)) != 0){
			if((rc & (1<<4)) != 0){
				rc = 99;  // controller lost arbitration
			}else if((rc & (1<<3)) != 0){
				rc = 98; // The transmitted data was not acknowledged. 
			}else if((rc & (1<<2)) != 0){
				rc = 97; // The transmitted address was not acknowledged.  
			}else if((rc & (1<<1)) != 0){
				rc = 96; // An error occurred on the last operation.   
			}else{
				I2C1_MCS_R = (1<<2); // send stop bit
				while((I2C1_MCR_R & (1<<0)) != 0);	// Wait for not busy
			}
		}
	}
	
	// ************************************************************
	// writeByte( uint8_t dataByte, uint8_t conditions )
	// ************************************************************
	void writeByte( uint8_t dataByte, uint8_t conditions )
	{
		I2C1_MDR_R = dataByte; 							// Set the data
		I2C1_MCS_R = conditions;						// run, start, etc
		while((I2C1_MCS_R & (1<<0)) != 0);	// Wait for not busy
		checkMCS();
	}
	
	
	// ************************************************************
	// readByte()
	// ************************************************************
	uint8_t readByte(){
		int retryCounter = 1;
		do{
			while(I2C1_MCS_R&I2C_MCS_BUSY){};				// wait for I2C ready
//			I2C1_MSA_R = (0x3D<<1)&0xFE;    				// MSA[7:1] is slave address
			I2C1_MSA_R |= 0x01;              				// MSA[0] is 1 for receive
			I2C1_MCS_R = run_start_stop;
			while(I2C1_MCS_R&I2C_MCS_BUSY){};				// wait for transmission done
			checkMCS();	
			retryCounter = retryCounter + 1;        // increment retry counter
		}                                         // repeat if error
		while(((I2C1_MCS_R&(I2C_MCS_ADRACK|I2C_MCS_ERROR)) != 0) && (retryCounter <= 100));
		return (I2C1_MDR_R&0xFF);          				// usually returns 0xFF on error
	}
	
	uint16_t x, y, z;
	// ************************************************************
	// read2Bytes()
	//
	// (1<<0) run
	// (1<<1)	start
	// (1<<2)	stop
	// (1<<3)	ack	
	// ************************************************************
	uint16_t read2Bytes(){
		
		uint8_t data1,data2;
		int retryCounter = 1;
		do{
			
			data1=0xAB;
			data2=0xAB;
			while(I2C1_MCS_R&I2C_MCS_BUSY){};				// wait for I2C ready
			I2C1_MCS_R = run_ack;
			while(I2C1_MCS_R&I2C_MCS_BUSY){};				// wait for transmission done
			checkMCS();	
			data1 = (I2C1_MDR_R);       				// MSB data sent first
			
			I2C1_MCS_R = run_ack;
			while(I2C1_MCS_R&I2C_MCS_BUSY){};				// wait for transmission done
			data2 = (I2C1_MDR_R);       				// LSB data sent last
			x = (data1<<8)+data2; 
				
			//
			// y
			// 
			data1=0xAB;
			data2=0xAB;
			while(I2C1_MCS_R&I2C_MCS_BUSY){};				// wait for I2C ready
			I2C1_MCS_R = run_ack;
			while(I2C1_MCS_R&I2C_MCS_BUSY){};				// wait for transmission done
			data1 = (I2C1_MDR_R&0xFF);       				// MSB data sent first
			
			I2C1_MCS_R = run_ack;
			while(I2C1_MCS_R&I2C_MCS_BUSY){};				// wait for transmission done
			data2 = (I2C1_MDR_R&0xFF);       				// LSB data sent last
			y = (data1<<8)+data2; 

			//
			// z
			// 
			data1=0xAB;
			data2=0xAB;
			while(I2C1_MCS_R&I2C_MCS_BUSY){};				// wait for I2C ready
			I2C1_MCS_R = run_ack;
			while(I2C1_MCS_R&I2C_MCS_BUSY){};				// wait for transmission done
			data1 = (I2C1_MDR_R&0xFF);       				// MSB data sent first
			
			I2C1_MCS_R = run_stop_ack;
			while(I2C1_MCS_R&I2C_MCS_BUSY){};				// wait for transmission done
			data2 = (I2C1_MDR_R&0xFF);       				// LSB data sent last
			z = (data1<<8)+data2; 
				
			retryCounter = retryCounter + 1;        // increment retry counter
		}                                         // repeat if error
		while(((I2C1_MCS_R&(I2C_MCS_ADRACK|I2C_MCS_ERROR)) != 0) && (retryCounter <= 100));
		return (data1<<8)+data2;                  // usually returns 0xFFFF on error
}
	
void GPIO_I2C1_Init(){
	// ***********************************************************************	
	// I2C_Init()
	//
	// PA6-SCL, PA7-SDA
	// ***********************************************************************	
	SYSCTL_RCGCI2C_R = (1<<1);						// Enable the I2C clock using I2C1
	SYSCTL_RCGCGPIO_R  = (1<<0);					// Enable clock on PortA
	GPIO_PORTA_AFSEL_R = (1<<6)|(1<<7);		// Alternate function Select
	GPIO_PORTA_DEN_R = (1<<6)|(1<<7);			// Digital Enable
	GPIO_PORTA_ODR_R = (1<<7);						// Enable open drain (SDA) pin.
	GPIO_PORTA_PCTL_R = (3<<28)|(3<<24);	// Configure PCM Fields 
	I2C1_MCR_R = (1<<4);									// Identify as Master
	I2C1_MTPR_R = (7<<0);									// Set the clock speed.
}	
	
uint16_t msb_x, msb_y;

int main(void){
	// ***********************************************************************	
	// main()
	//
	// (1<<4) == Move a 1 into position 4
	// 0x1E 0x3C 0x3D
	// ***********************************************************************	
  PLL_Init();
	GPIO_I2C1_Init();

	setSlaveAddress(0x1E);					// write address
	setRW(0);												// write

	// (8-average, 15 Hz default, normal measurement)
	writeByte(0x3C,run_ack); 							
	writeByte(0x00,run_ack); 							
	writeByte(0x70,run_stop_ack); 				
	// (Gain=5, or any other desired gain)
	writeByte(0x3C,run_ack); 				
	writeByte(0x01,run_ack); 				
	writeByte(0xA0,run_stop_ack); 				
	// (Continuous-measurement mode)
	writeByte(0x3C,run_ack); 				
	writeByte(0x02,run_ack); 		
	writeByte(0x00,run_stop_ack); 				
		
	Delay(10000);

	while(1)
	{
		
		writeByte(0x3D,run_ack); 			
		writeByte(0x06,run_stop_ack); 			
	
		setRW(1);
		read2Bytes();
		
		setRW(0);
		writeByte(0x3C,run_ack); 							
		writeByte(0x03,run_stop_ack); 							
	
	}
	
	
}

  • Hello Randy,

    My first suggestion (and honest one) is to move away from DRM style of access to TivaWare if you are new to the device.

    It will simplify a lot of the code reading, possible issues of fault (I see one in the code) and take care of nuances of a device. Especially PLL_Init is not a simple function.

    Regards
    Amit