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.

MSp430 external EEPROM with I2C

Hi there.

I have a very strange problem regarding my MSP420F2272.  I would like to address an external EEPROM to store some values and read them back later. The EEPROM is a AT24C512B and needs to be addressed wit 2 Bytes. 

Reading is working fine. i'll transmit 2 address bytes send a restart and read all the bytes i request. 



Writing instead is finished with a stop condition after the first address byte.  

 +


I set a breakpoint to every stop condition. none was reached.  I have absolutly no idea what's going wrong. 


Attached my I2C Code:


/*
 * I2C.c
 *
 *  Created on: 02.08.2012
 *      Author: l-doerner
 */

#include "I2C.h"

UINT8 History_Page				=	HISTORY_START_PAGE;
UINT8 History_Position			=	0;

UINT16	Address					=	0;
UINT16	Length						=	0;

UINT8	*pTransmit					=	0;
UINT8	*pReceive					=	0;
UINT8	*pAddress					=	0;

UINT8	Target							=	WRITE_HISTORY;

UINT8	Addressing_Flag			=	0;

void fnInitI2C			(void)
{
	UCB0CTL1 = UCSWRST;
	/* I2C | master | single master | synchronous mode | slave address 7bit | own address 7bit */
	UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC;

	/* enable SW reset | use SMCLK | normal ACK | no START | no STOP | reciver */
	UCB0CTL1 = UCSSEL_2 + UCSWRST;

	/* 12MHz/120 = 100KHz */
	UCB0BR0 = 0x78;
	UCB0BR1 = 0x00;
	//UCB0BR0 = 0x12;                             // set prescaler
	//  UCB0BR1 = 0;
	UCB0I2CSA = EEPROM;
	UCB0CTL1 &= ~UCSWRST;
	UCB0I2CIE = UCNACKIE;			/* Not-acknowledge interrupt enable*/
}

void fnStoreHistory 	(void)
{
	fnInitI2C();
	Target						=		WRITE_HISTORY;
	Address						=		History_Page	*	128 + History_Position;
	pAddress					=		(UINT8 *)& Address;
	pTransmit				=		(UINT8	*)	&history.Cylce;
	Length						=		sizeof(history);
	Addressing_Flag		=		1;
	IE2 			 					= 		UCB0TXIE;			/* USCI_B0 transmit interrupt enable */
	UCB0CTL1 				|= 	UCTR + UCTXSTT;		/* start condition I2C transmit */
	while (UCB0STAT & UCBBUSY);
}

void fnStoreSystemValues	(void )
{
	fnInitI2C();
	Target						=		WRITE_SYSTEM;
	Address					=		0x01;
	pAddress					=		(UINT8 *) &Address;
	pTransmit				=		(UINT8	*)	&System.Cycle_Count;
	Length						=		sizeof(System);
	Addressing_Flag		=		1;
	IE2 			 				= 		UCB0TXIE;			/* USCI_B0 transmit interrupt enable */
	UCB0CTL1 				|= 	UCTR + UCTXSTT;		/* start condition I2C transmit */
	while (UCB0STAT & UCBBUSY);
}

void fnReadHistory	(UINT16 Start_Address, UINT16 Length)
{
	fnInitI2C();
	Target						=		READ_HISTORY;
	Address						=		Start_Address;
	pAddress					=		(UINT8 *) &Address;
	Length						=		Length;
	Addressing_Flag		=		1;
	IE2 			 					= 		UCB0TXIE;			/* USCI_B0 transmit interrupt enable */
	UCB0CTL1 				|= 	UCTR + UCTXSTT;		/* start condition I2C transmit */
	while (UCB0STAT & UCBBUSY);
}

void fnReadSystemValue	(void)
{
	fnInitI2C();
	Target						=		READ_SYSTEM;
	Address						=		0x0000;
	pAddress					=		(UINT8 *) &Address;
	pReceive					=		(UINT8	*)&	System.Cycle_Count;
	Length						=		sizeof(System);
	Addressing_Flag		=		1;
	IE2 			 					= 		UCB0TXIE;			/* USCI_B0 transmit interrupt enable */
	UCB0CTL1 				|= 	UCTR + UCTXSTT;		/* start condition I2C transmit */
	while (UCB0STAT & UCBBUSY);
}

void	fnCheck_Page_Overflow(void)
{
	History_Position++;

	if(History_Position		==	128)
	{
		History_Position		=		0;
		if (History_Page		== 	511)
		{
			History_Page		=		HISTORY_START_PAGE;
		}
		else
		{
			History_Page++;
		}
		Addressing_Flag		=		1;
		Address						=		History_Page	*	128 + History_Position;
		pAddress					=		(UINT8 *) &Address;
	}
}


#pragma vector=USCIAB0RX_VECTOR
__interrupt void USCIAB0RX_ISR(void)
{
	if (UCB0STAT & UCNACKIFG)
	{
		UCB0CTL1 |=UCTXSTP;			// if slave send NACK, master generate STOP
		UCB0STAT &= ~UCNACKIFG;		// reset Not-acknowledge received interrupt flag
	}
}

#pragma vector=USCIAB0TX_VECTOR
__interrupt void USCIAB0TX_ISR (void)
{
	static UINT8 Address_length		=	2;

	if (IFG2 & UCB0RXIFG)				// UCB0RXIFG is set when UCB0RXBUF has received a complete character
	{
		switch (Target) {
			case READ_HISTORY:
				if ( Length == 1)		// all Bytes read
				{
					UCB0CTL1 |= UCTXSTP;	// stop condition I2C
					IFG2 					&= 	~UCB0TXIFG;		// USCI_B0 clear transmit interrupt flag
			//		UARTBUFFER= UCB0RXBUF;						//UARTBUFFER todo
				}
				else
				{
			//		UARTBUFFER= UCB0RXBUF;
					Length--;
				}
				break;
			case READ_SYSTEM:
				if ( Length == 1)		// all Bytes read
				{
					UCB0CTL1 |= UCTXSTP;	// stop condition I2C
					IFG2 					&= 	~UCB0TXIFG;		// USCI_B0 clear transmit interrupt flag
					*pReceive = UCB0RXBUF;
					Length--;
				}
				else
				{
					*pReceive = UCB0RXBUF;
					pReceive++;
					Length--;
				}
				break;
			default:
				break;
		}
	}
	else
	if (IFG2 & UCB0TXIFG)
	{
		if (Addressing_Flag)
		{
			if(Address_length == 0)
			{
				Addressing_Flag		=	0;
				Address_length		=	2;
				fnInitI2C();

				switch (Target)
				{
					case WRITE_HISTORY:
						UCB0TXBUF		=	*pTransmit;
						pTransmit++;
						Length--;
						fnCheck_Page_Overflow();
						break;
					case WRITE_SYSTEM:
						UCB0TXBUF		=	*pTransmit;
						pTransmit++;
						Length--;
						break;
					case READ_HISTORY:
					case READ_SYSTEM:
						IFG2 					&= 	~UCB0TXIFG;		// USCI_B0 clear transmit interrupt flag
						IE2 						 = 	UCB0RXIE;					/* USCI_B0 receive interrupt enable */
						UCB0CTL1				&=		~UCTR;
						UCB0CTL1 				|= 	UCTXSTT;		/* start condition I2C receive */
						break;
					default:
						break;
				}
			}
			else
			{
				UCB0TXBUF 		= 		*pAddress;
				delay(20);
				pAddress++;
				Address_length--;
			}
		}
		else
		{
			if ( Length == 1)
			{
				UCB0CTL1 |= UCTXSTP;	// stop condition I2C
				IFG2 &= ~UCB0TXIFG;		// USCI_B0 clear transmit interrupt flag
			}
			else
			{
				UCB0TXBUF = *pTransmit;
				pTransmit++;
				Length--;
				fnCheck_Page_Overflow();
			}
		}
	}
}

Thx for the help.


  • Lars D said:

    Writing instead is finished with a stop condition after the first address byte.

    Where do you see that description in the datasheet for the Atmel I2C EEPROM datasheet?  I don't see that behavior described in Figure 6-2 of the Atmel AT24C512B datasheet.

  • Your code dlogic is messed-up.

    In the TX part of your ISR you call for fnInitI2C(). However, the transfer is already ongoing. So the first thing you do in this ISR is to reset the USCI instead of simply doing hat the interrupt means: feeding the next byte to be sent.
    Even if you wouldn't do this and break teh communication, your code would send and send forever as there is no break condition that will end the transfer when Length reaches 0.

    You should re-design the ISR logic.Completely. The diagrams in the users guide are a big help.

  • Actually it was the second use of  fnInitI2C();

    Netherles there are break conditions. They are are little hidden at the end of the code. 

    I'm not sure with checking the length to stop. 

    When I use Length == 0 to stop I can see one more byte then i wanted to read. That's why i use Length == 1. 

    Is the Nack Byte thrown away?

**Attention** This is a public forum