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: Help with I2C Interface to MCP4725 DAC

Part Number: EK-TM4C123GXL

Hello, I cannot make the I2C work properly to interface with the MCP4725 DAC. Any help is appreciated. 

Here is my code: 

unsigned long *RCGCI2C = (unsigned long*) 0x400FE620; //Base 0x400F.E000, offset 0x620
unsigned long *RCGCGPIO = (unsigned long*) 0x400FE608; // Base 0x400F.E000, offset 0x608
unsigned long *GPIOAFSEL = (unsigned long*) 0x40005420; //Base port B 0x4000.5000, offset 0x420
unsigned long *GPIODEN = (unsigned long*) 0x4000551C; //Base port B 0x4000.5000, offset 0x51C
unsigned long *GPIOODR = (unsigned long*) 0x4000550C; //Base port B, offset 0x50C
unsigned long *GPIOCTL = (unsigned long*) 0x4000552C; //base port B, offset 0x52C
unsigned long *GPIOPUR = (unsigned long*) 0x40005510; //base port B, offset 0x510
unsigned long *GPIOCR = (unsigned long*) 0x40005524; //base port B, offset 0x524
unsigned long *GPIOLOCK = (unsigned long*) 0x40005520; //base port B, offset 0x520

unsigned long *I2CMCR = (unsigned long*) 0x40020020; //base I2C0 0x4002.0000, offset 0x020
unsigned long *I2CMTPR = (unsigned long*) 0x4002000C; //base I2C0 0x4002.0000, offset 0x00C
unsigned long *I2CMSA = (unsigned long*) 0x40020000; //base i2c0, offset 0x000
unsigned long *I2CMDR = (unsigned long*) 0x40020008; //base i2c0, offset 0x008
unsigned long *I2CMCS = (unsigned long*) 0x40020004; //base i2c0, offset 0x004


void clock_setup() {	
	//RCC       pg 254, base 0x400F E000, offset 0x060
	//RCC2      pg 260, base 0x400F E000, offset 0x070
	//Step 1
	//Bypass the PLL and system clock divider by setting the bypass2 bit and clearing the usesys2
	//bit, thereby configuring the microcontroller to run off a "raw" clock source" and allowing 
	//for the new pll configuration to be validated before switching the clock to the PLL

	*rcc2 = *rcc2 | 1 << 31; // Set USERCC2 to 1, using the RCC2 register instead of the RCC register
	*rcc = *rcc & 0xFFBFFFFF; //Clear USESYSDIV, set the 22nd bit of rcc to 0
	*rcc2 = *rcc2 | 1 << 11; // Set BYPASS2 to 1, the 11th bit of RCC2 (overwrites rcc)

	//Step 2
	//Select the crystal value (XTAL) and oscillator source (OSCSRC), and clear
	//the PRDWN bit in rcc2
	*rcc = *rcc & 0xFFFFF83F; //clear the xtal values bit 10:6 in RCC register
	*rcc = *rcc | 0x00000540; //set the xtal values to the equivalent of 0x15 in bits 10:6 for 16Mhz crystal
	*rcc2 = *rcc2 & 0xFFFFFF8F; //select the mainosc of oscsrc2 in bits 6:4 of rcc2: 0x0 (also clears the bits)
	*rcc2 = *rcc2 | 0x00000010; //set the oscillator to precision oscillator, 0x1
	*rcc2 = *rcc2 & 0xFFFFDFFF;	// Clear the PWRDWN2 by setting 0 to bit 13 in RCC2 to cause the PLL to operate normally

	//Part 3 - choose speed
	//*rcc = *rcc | 1 << 22; //set bit 22 of RCC to use system division
	//Select Sysdiv2 in RCC2 bit 28:23 , 0x3 is for /4 = 50Mhz
	*rcc2 = *rcc2 & 0xE07FFFFF ; //clear sysdiv2 in rcc2
	//set pointers to memory locations at base + offset
	//unsigned long *rcc = (unsigned long*) 0x400FE060;
	//unsigned long *rcc2 = (unsigned long*) 0x400FE070;

	//table 5-5 for selecting sysdiv2, from freq/1 to freq/64, denominator is (wanted division) - 1 in hex. for example:
	//freq/10 = 0x09 (9 in hex)
	//0x03 is 50Mhz
	*rcc2 = *rcc2 | 0x03 << 23; //set the sysdiv2 to the appropriate speed, use the shift operator because its 5 bits long but only takes 4 bit divisors

	//Step 4
	//wait for PLL to lock
	//wait for RIS register bit 6 to be 1 which indicates the PLL is locked
	wait_for_pll();

	//RCGCGPIO, pg 340, address 0x400FE000, offset 0x608, sends a clock to a specific port, bit 5 is port F
	//set bit 5 to 1 to enable the clock to go to port f
	unsigned long *RCGC = (unsigned long*) 0x400FE608;
	*RCGC = *RCGC | 0x20;
}

void i2c_configure() {
	// Instructions from pg. 1015 in data sheet, 16.4.1
	// 1. Enable the I2C clock using the RCGCI2C register in the system control module on page 348
		*RCGCI2C = *RCGCI2C | 1; //setting bit 0 to high enables I2C module 0

	// 2. Enable the clock to the GPIO module via RCGCGPIO, pg 340. Refer to table 23-5 on page 1351 for which GPIO port to enable. 
	// I2C module 0 is on Port B, so we set bit 1 to high
		*RCGCGPIO = *RCGCGPIO | (1<<1); 

	// 3. In the GPIO module, enable the appropriate pins for alternate function using GPIOAFSEL (page 671). Refer to table 23-4 page 1344
	// for which GPIOs to configure
	// pin 47 for i2c0 scl (pb2), pin 48 for i2c0 sda (pb3)
	// also our DAC requires pull up resistors according to the data sheet
	// the tiva requires modifying GPIOLOCK and GPIOCR to modify GPIOPUR
		*GPIOLOCK = *GPIOLOCK | 0x4C4F434B; //the only value that can be written here from tiva data sheet
		*GPIOCR = *GPIOCR | (1<<2) | (1<<3); //allow changing of bits 2 and 3 in other registers
		*GPIOAFSEL = *GPIOAFSEL | (1<<2) | (1<<3); // alternate function select for pins 2 and 3
		*GPIODEN = *GPIODEN | (1<<2) | (1<<3); // enable digital output for pins 2 and 3
		*GPIOPUR = *GPIOPUR | (1<<2) | (1<<3); //enable pull up resistors on pins 2 and 3

	// 4. Enable the I2CSDA pin for open-drain operation, see page 676
		*GPIOODR = *GPIOODR | (1<<3); //set the i2C data pin (pb3) of GPIO port B to open drain

	// 5. Config the PMCn fields in the GPIOCTL reg to assign the I2C signal to the appropriate pins, see page 688 and table 23-5 on page 1351
	// table 23-5 says I need to put a 3 in GPIOCTL pmc for pin 2 and pin 3
		*GPIOCTL = *GPIOCTL | (3<<8) | (3<<12); //mux gpio to i2c by setting a 3 in pmc2 and pmc3 

	// 6. Initialize I2C Master by writing the I2CMCR reg with value of 0x000.0010
		*I2CMCR = *I2CMCR | (1<<4); //initializes master function

	// 7. Set the desired SCL clock speed of 100 Kbps by writing the I2CMTPR (i2c master time period) reg with value. 
	// can choose 3 speesds, choose 100K arbitrarily
	// TPR = (sysclk/ (2*(SCL_LP + SCL_HP)*SCL_CLK))-1
	// TPR = (50MHz/(2*(6+4)*100000))-1
	/****************************************************
	//assuming system clock is 50Mhz, may need to change
	***************************************************/ 
	// TPR = 24
	// write the I2CMTPR reg with value of 0x0000.0024
		*I2CMTPR = *I2CMTPR | (0x24<<0); 

	// 8. Specify the slave address of the master and that the next op is transmit by writing I2CMSA
	// i2cmsa bits 7-1 are the slave address, the mcp4725 chip slave address is (not sure), or 0x62 is internet guides
	// we also need to set next operation to transmit, by setting bit 0 (low for transmit, high for receive)
	// therefore need to write (not sure)
	// this is sent automatically each time as the first byte

	
	// 9. Place data(byte) to be transmitted in the data reg by writing the I2C Master Data register (I2CMDR) 
	// reg with the data, 1 byte in length
	// The device takes 4 bytes of data, and transmits an Acknowledge bit after receiving each byte
	//
	//     Byte 1				Byte 2				Byte 3				Byte 4
	// S |7|6|5|4|3|2|1|0| A |7|6|5|4|3|2|1|0| A |7|6|5|4|3|2|1|0| A |7|6|5|4|3|2|1|0| A
	//   |  Dev  |Addr |R|   |C2-C0| x |PDs|x|   |     12 Bit data tx        |x x x x|
	//   |  Code |Bits |W|                       | D11 - D0                  |
	//
	//S: start bit sent by master
	//A: received bit set by slave after each byte
	//Dev Code: Slave Address, 1100 by default
	//Address Bits: A2, A1, A0. A2/A1 are 0 by default, A0 is user defined
	//R/W: what action peforming on slave register
	//C2/C1/C0: what type of read/write operation -- '010' for write to DAC register
	//PDs: set both to 0 for normal operation
	//Dn: transmit data, see below for how the output voltage is affected
	//			 Vdd * Dn
	//  Vout = ------------
	//            4096

	// 10. Initiate byte 1 & 2 transmit of the data from Master to Slave by writing the I2CMCS reg
	// (STOP, START, RUN), use the "write only control register" bit map
	// bit 0 RUN
	// bit 1 START
	// bit 2 StOP, if this bit is not high, will transmit continually

	// 11. Wait until the transmission completes by polling the I2CMCS reg's BUSBSY bit until it has been cleared
	// i2cmcs busbsy is bit 6
	// value of 1 indicates i2c still busy
	// 12. Check the error bit in the I2CMCS reg to confirm the transmit was ackonwledged
	// transmitted MSB first

	//set slave address
		*I2CMSA = *I2CMSA | 0xC0; // device address is 1100, plus the An bits = 000, adding the R/W bit makes 0x1100.0000
	//byte 1 & 2
		*I2CMDR = *I2CMDR | 0x40;
		while ( (*I2CMCS & 1<<6) != 0);
		*I2CMCS = *I2CMCS | (1<<1) | (1<<0); //Start & Run
		while ( (*I2CMCS & 1<<0) != 0);
		//**************error check
		if ( (*I2CMCS & 1<<1) != 0) { 	//check for error	
			*I2CMCS = *I2CMCS | (1<<2); //send stop if error
			while ( (*I2CMCS & 1<<0) != 0);
		}
		*I2CMCS = *I2CMCS | (1<<0); //Run

	//byte 3
		while ( (*I2CMCS & 1<<0) != 0);
		//**************error check
		if ( (*I2CMCS & 1<<1) != 0) { 	//check for error	
			*I2CMCS = *I2CMCS | (1<<2); //send stop if error
			while ( (*I2CMCS & 1<<0) != 0);
		}
		//**************
		*I2CMDR = *I2CMDR | (0x00); //set output voltage
		*I2CMCS = *I2CMCS | (1<<0); //send run bit

	//byte 4
		while ( (*I2CMCS & 1<<0) != 0);
		//**************error check
		if ( (*I2CMCS & 1<<1) != 0) { 	//check for error	
			*I2CMCS = *I2CMCS | (1<<2); //send stop
			while ( (*I2CMCS & 1<<0) != 0);
		}
		//**************error check
		*I2CMDR = *I2CMDR | (0x00); //set output voltage
		*I2CMCS = *I2CMCS | (1<<0); //send Stop and Run
		
		while ( (*I2CMCS & 1<<0) != 0);
		//**************
		if ( (*I2CMCS & 1<<1) != 0) { 	//check for error	
			*I2CMCS = *I2CMCS | (1<<2); //send stop
			while ( (*I2CMCS & 1<<0) != 0);
		}
		//**************
}

int main() {
	clock_setup();
	i2c_configure();
}