Posted by Mike Raines April 16, 2014
Hi Folks,
Mystery solved. Well, it wasn't much of a mystery anyway. Thanks to all who tried to help. The almost obvious answer is that the extra statements just provided a delay. I have replaced them with a 15 usec delay between sending bytes, and a 1 ms delay following the stop condition sent. It seems I need to pay closer attention to the timing specs. I need to re-check delays used for bitbanging a DAC, an LCD controller, and a RTC right off the top of my head.....
Thanks again,
Mike Raines

Beginning Microcontrollers with the MSP430

Posted by Mike Raines April 15, 2014
Steve,

Thanks for the reply. Your explanation of the case 10 problem seems reasonable and as I said, I don't mind removing the extra diagnostic code to make it work properly. I still can't see exactly why adding the extra diagnostic statements to case 12 when transmitting the address bytes then causes the read from that address to work; and removing the extra statements causes the read to fail.

You suggest making sure the transmit buffer is empty before stopping the i2c process. It seems that this isr (which came from a TI example program) uses the variable TXByteCtr to send the correct # of bytes. In all my test cases so far, I send and receive one integer, 2 bytes, so TXByteCtr is set to 2 before turning control over to the isr and the isr decrements the counter after sending each byte. Perhaps you , or someone else, could show me what is wrong.

Thanks again,
Mike Raines

________________________________
From: m... [mailto:m...] On Behalf Of Steve Mayfield
Sent: Tuesday, April 15, 2014 12:27 PM
To: m...
Subject: Re: [msp430] MSP430F5438A eeprom isr works ONLY with extra print statements??

In your read routine:
sprintf(outBuf, "case 10:%X", UCB2RXBUF);
will pull a character out of the UART (doesn't leave it in the buffer if
another character is available) so when you get to
*PRxData ++ = UCB2RXBUF;
it stores the next character if another character is available. The correct
method is to store the contents of UCB2RXBUF in a local variable and then
use the local variable for remainder of the routine.

In the XMIT ISR, you need to make sure the transmit buffer is empty before
you stop the I2C process.

----- Original Message -----
From: m...@hofferflow.com
To: m...
Sent: Tuesday, April 15, 2014 07:43
Subject: [msp430] MSP430F5438A eeprom isr works ONLY with extra print
statements??

Hi Folks,

I am attempting to write/read a Microchip 24FC1025 eeprom using the
intrinsic i2c on a Texas Instruments MSP430F5438A chip. This may be a
mistake because I got no hits when searching the Microchip forum for msp430
or F5438. Has anyone done this successfully and, if so, what are the
pitfalls to watch out for?

It is my understanding that this eeprom has two slave addresses, one for
each half of the memory. The slave address for the lower half is 1010 000
(0x50) and for the upper half is 1010 100 (0x54). Before reading/writing
the eeprom I must insure I'm using the proper slave address. This is an
example of switching to block 1:
//======================================================================//======================================================================
void InitializeUcb2Block1(void) // eeprom interface
{

UCB2CTL1 |= UCSWRST; // Enable SW reset
UCB2CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous
mode
UCB2CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset
UCB2BR0 = 12; // fSCL = SMCLK/12 = ~100kHz
UCB2BR1 = 0;
UCB2I2CSA = 0x50; // Slave Address is 0x50
1010 000
UCB2CTL1 &= ~UCSWRST; // Clear SW reset, resume
operation
UCB2IE |= UCTXIE; // Enable TX interrupt
UCB2IE |= UCRXIE; // enable rx interrupt

} // end function void InitializeUcb2ForI2cToEeprom(void)

//======================================================================//======================================================================
// ================== ensure slave address points to block 1
=============
if (UCB2I2CSA != 0x50) // if not block 1
{
InitializeUcb2Block1();
} // end if not block 1

DelayMs(1); // test delay

This seems to work fine.

For writing, I first disable a write-protect pin P9.0 (set the pin low). I
place the high and low bytes of the address into elements 0 and 1 of an
array TxData, followed by the data bytes to place in the eeprom starting at
this address. I then set a pointer used by the USCIB2 ISR (interrupt
service routine) to the start of the array and another variable used by the
isr, TXByteCtr, to the number of bytes to write. I then turn the process
over to the intrinsic TI I2C by executing:
UCB2CTL1 |= UCTR + UCTXSTT; and while(UCB2CTL1 & UCTXSTP); The
write-protect pin is enabled when the isr clocks out the last byte.

For reading, I disable the write-protect pin just to send the address and
follow the write procedure placing just the read address in the array and
setting TXByteCtr to 2. It is my understanding that the isr now sends the
address and that this places the eeprom internal address pointer to the
address I sent. I then set a pointer used by the isr to a buffer to receive
the read bytes, and I set another variable available to the isr to the
number of bytes to read. I then switch from write to read functionality by
executing: UCB2CTL1 &= ~UCTR; and UCB2CTL1 |UCTXSTT;

This seems to work most of the time, but I'm worried about several
anomolies. Recently, I noticed that on a read, the isr only accesses every
other byte. It's like the memory pointer is incrementing by 2 instead of 1.
I discovered if I removed the three print statements from case 10 of the
isr, the read worked normally.

Just yesterday, while implementing this to several write/read to/from eeprom
instances, I removed the three "print" statements from case 12 of the isr
because my PC printout was getting crowded. To my great surprise, the read
operations stopped working. I put the statements back, and the read
operations work again.

To summarize, it did not concern me greatly that the extra isr statements in
case 10 caused read problems, and I had no heartburn about removing them.
The (seeming) fact that the extra statements are necessary for case 12 to
work is scary. I do not like working with algorithms that are this touchy.

Can someone please shed some light on this problem, and a possible solution?
This is the isr:

//===========================================================//===========================================================#pragma vector = USCI_B2_VECTOR // TI intrinsic i2c isr
__interrupt void USCI_B2_ISR(void)
{
unsigned char iv = (unsigned char)UCB2IV;
// sprintf(outBuf, "UCB2IV is: %X", iv);
// TxBuffer(outBuf, 30, 1);

// switch(__even_in_range(UCB2IV,12))
switch(__even_in_range(iv,12))
{
case 0: break; // Vector 0: No interrupts
case 2: break; // Vector 2: ALIFG
case 4: break; // Vector 4: NACKIFG
case 6: break; // Vector 6: STTIFG
case 8: break; // Vector 8: STPIFG
case 10:

// TxBuffer("case 10:", 10, 1);
RXByteCtr --; // decrement rx byte counter
if (RXByteCtr) // if bytes to read
{
// sprintf(outBuf, "case 10:%X", UCB2RXBUF);
// TxBuffer(outBuf, 30, 1);
*PRxData ++ = UCB2RXBUF; // move data byte to buffer
if (RXByteCtr == 1) // if next-to-last byte
UCB2CTL1 |= UCTXSTP; // generate i2c stop
condition
}
else
{
// sprintf(outBuf, "case 10:%X", UCB2RXBUF);
// TxBuffer(outBuf, 30, 1);
*PRxData = UCB2RXBUF; // move final byte to buffer
// __bic_SR_register_on_exit (LPM0_bits); // exit with active cpu
// __bic_SR_register_on_exit (LPM3_bits); // exit with active cpu
} // end if bytes to read else

break; // Vector 10: RXIFG
case 12: // Vector 12: TXIFG

TxBuffer("case 12: ", 12, 0);
if (TXByteCtr) // Check TX byte counter
{
sprintf(outBuf, "%X", *PTxData);
TxBuffer(outBuf, 30, 1);

UCB2TXBUF = *PTxData++; // Load TX buffer if bytes to
send
TXByteCtr--; // Decrement TX byte counter
}
else
{
UCB2CTL1 |= UCTXSTP; // I2C stop condition
UCB2IFG &= ~UCTXIFG; // Clear USCI_B0 TX int flag
TxBuffer("***STOP***", 30, 1);
P9OUT |= BIT0; // write-protect on

// __bic_SR_register_on_exit(LPM0_bits); // Exit LPM0
// __bic_SR_register_on_exit(LPM3_bits); // Exit LPM3
} // end if bytes to send

break;
default: break;
} // end switch
} // end function __interrupt void USCI_B2_ISR(void)

//======================================================================//======================================================================
Mike Raines

size=1 width="100%" noshade color="#a0a0a0" alignter>
No virus found in this message.
Checked by AVG - www.avg.com
Version: 2014.0.4355 / Virus Database: 3882/7344 - Release Date: 04/14/14
Posted by Mike Raines April 15, 2014
Thanks for the response. As I said, sometimes it appears I can, other times I can't, and sometimes I have to. ( -;) This TxBuffer() is a routine I wrote that uses a uart to send short msgs to a PC for viewing on HyperTerminal. It is pretty simple:

#if 1 // usb version // (send until nullChar) // OVERLOADED TO HANDLE CONST STRINGS
void TxBuffer(const char* bufPtr, int charCount, int crlf)
{
const char* charPtr = bufPtr;
int i=0;

for (i=0; i {
if (*charPtr == nullChar)
{
__delay_cycles(1);
break; // exit for loop???
}
else
{
UCA1TXBUF = *charPtr;
while (UCA1STAT & UCBUSY);
charPtr ++;
}
} // end for i
if (crlf)
{
UCA1TXBUF =newLine;
while (UCA1STAT & UCBUSY);
UCA1TXBUF riageReturn;
while (UCA1STAT & UCBUSY);
} // end if crlf
} // end function TxBuffer

#endif // usb version

________________________________
From: m... [mailto:m...] On Behalf Of c...@gmail.com
Sent: Tuesday, April 15, 2014 11:17 AM
To: m...
Subject: [msp430] Re: MSP430F5438A eeprom isr works ONLY with extra print statements??

Mike,

Are you sure you can use the TxBuffer() routine within an interrupt routine? I've had different problems when using debug output routines in interrupt routines. Mostly by blocking other interrupts firing (and missing data).

size=1 width="100%" noshade color="#a0a0a0" alignter>
No virus found in this message.
Checked by AVG - www.avg.com
Version: 2014.0.4355 / Virus Database: 3882/7344 - Release Date: 04/14/14
Posted by Steve Mayfield April 15, 2014
In your read routine:
sprintf(outBuf, "case 10:%X", UCB2RXBUF);
will pull a character out of the UART (doesn't leave it in the buffer if
another character is available) so when you get to
*PRxData ++ = UCB2RXBUF;
it stores the next character if another character is available. The correct
method is to store the contents of UCB2RXBUF in a local variable and then
use the local variable for remainder of the routine.

In the XMIT ISR, you need to make sure the transmit buffer is empty before
you stop the I2C process.
----- Original Message -----
From: m...@hofferflow.com
To: m...
Sent: Tuesday, April 15, 2014 07:43
Subject: [msp430] MSP430F5438A eeprom isr works ONLY with extra print
statements??

Hi Folks,

I am attempting to write/read a Microchip 24FC1025 eeprom using the
intrinsic i2c on a Texas Instruments MSP430F5438A chip. This may be a
mistake because I got no hits when searching the Microchip forum for msp430
or F5438. Has anyone done this successfully and, if so, what are the
pitfalls to watch out for?

It is my understanding that this eeprom has two slave addresses, one for
each half of the memory. The slave address for the lower half is 1010 000
(0x50) and for the upper half is 1010 100 (0x54). Before reading/writing
the eeprom I must insure I'm using the proper slave address. This is an
example of switching to block 1:
//======================================================================//======================================================================
void InitializeUcb2Block1(void) // eeprom interface
{

UCB2CTL1 |= UCSWRST; // Enable SW reset
UCB2CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous
mode
UCB2CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset
UCB2BR0 = 12; // fSCL = SMCLK/12 = ~100kHz
UCB2BR1 = 0;
UCB2I2CSA = 0x50; // Slave Address is 0x50
1010 000
UCB2CTL1 &= ~UCSWRST; // Clear SW reset, resume
operation
UCB2IE |= UCTXIE; // Enable TX interrupt
UCB2IE |= UCRXIE; // enable rx interrupt

} // end function void InitializeUcb2ForI2cToEeprom(void)

//======================================================================//======================================================================
// ================== ensure slave address points to block 1
=============
if (UCB2I2CSA != 0x50) // if not block 1
{
InitializeUcb2Block1();
} // end if not block 1

DelayMs(1); // test delay

This seems to work fine.

For writing, I first disable a write-protect pin P9.0 (set the pin low). I
place the high and low bytes of the address into elements 0 and 1 of an
array TxData, followed by the data bytes to place in the eeprom starting at
this address. I then set a pointer used by the USCIB2 ISR (interrupt
service routine) to the start of the array and another variable used by the
isr, TXByteCtr, to the number of bytes to write. I then turn the process
over to the intrinsic TI I2C by executing:
UCB2CTL1 |= UCTR + UCTXSTT; and while(UCB2CTL1 & UCTXSTP); The
write-protect pin is enabled when the isr clocks out the last byte.

For reading, I disable the write-protect pin just to send the address and
follow the write procedure placing just the read address in the array and
setting TXByteCtr to 2. It is my understanding that the isr now sends the
address and that this places the eeprom internal address pointer to the
address I sent. I then set a pointer used by the isr to a buffer to receive
the read bytes, and I set another variable available to the isr to the
number of bytes to read. I then switch from write to read functionality by
executing: UCB2CTL1 &= ~UCTR; and UCB2CTL1 |UCTXSTT;

This seems to work most of the time, but I’m worried about several
anomolies. Recently, I noticed that on a read, the isr only accesses every
other byte. It's like the memory pointer is incrementing by 2 instead of 1.
I discovered if I removed the three print statements from case 10 of the
isr, the read worked normally.

Just yesterday, while implementing this to several write/read to/from eeprom
instances, I removed the three “print” statements from case 12 of the isr
because my PC printout was getting crowded. To my great surprise, the read
operations stopped working. I put the statements back, and the read
operations work again.

To summarize, it did not concern me greatly that the extra isr statements in
case 10 caused read problems, and I had no heartburn about removing them.
The (seeming) fact that the extra statements are necessary for case 12 to
work is scary. I do not like working with algorithms that are this touchy.

Can someone please shed some light on this problem, and a possible solution?
This is the isr:

//===========================================================//===========================================================#pragma vector = USCI_B2_VECTOR // TI intrinsic i2c isr
__interrupt void USCI_B2_ISR(void)
{
unsigned char iv = (unsigned char)UCB2IV;
// sprintf(outBuf, "UCB2IV is: %X", iv);
// TxBuffer(outBuf, 30, 1);

// switch(__even_in_range(UCB2IV,12))
switch(__even_in_range(iv,12))
{
case 0: break; // Vector 0: No interrupts
case 2: break; // Vector 2: ALIFG
case 4: break; // Vector 4: NACKIFG
case 6: break; // Vector 6: STTIFG
case 8: break; // Vector 8: STPIFG
case 10:

// TxBuffer("case 10:", 10, 1);
RXByteCtr --; // decrement rx byte counter
if (RXByteCtr) // if bytes to read
{
// sprintf(outBuf, "case 10:%X", UCB2RXBUF);
// TxBuffer(outBuf, 30, 1);
*PRxData ++ = UCB2RXBUF; // move data byte to buffer
if (RXByteCtr == 1) // if next-to-last byte
UCB2CTL1 |= UCTXSTP; // generate i2c stop
condition
}
else
{
// sprintf(outBuf, "case 10:%X", UCB2RXBUF);
// TxBuffer(outBuf, 30, 1);
*PRxData = UCB2RXBUF; // move final byte to buffer
// __bic_SR_register_on_exit (LPM0_bits); // exit with active cpu
// __bic_SR_register_on_exit (LPM3_bits); // exit with active cpu
} // end if bytes to read else

break; // Vector 10: RXIFG
case 12: // Vector 12: TXIFG

TxBuffer("case 12: ", 12, 0);
if (TXByteCtr) // Check TX byte counter
{
sprintf(outBuf, "%X", *PTxData);
TxBuffer(outBuf, 30, 1);

UCB2TXBUF = *PTxData++; // Load TX buffer if bytes to
send
TXByteCtr--; // Decrement TX byte counter
}
else
{
UCB2CTL1 |= UCTXSTP; // I2C stop condition
UCB2IFG &= ~UCTXIFG; // Clear USCI_B0 TX int flag
TxBuffer("***STOP***", 30, 1);
P9OUT |= BIT0; // write-protect on

// __bic_SR_register_on_exit(LPM0_bits); // Exit LPM0
// __bic_SR_register_on_exit(LPM3_bits); // Exit LPM3
} // end if bytes to send

break;
default: break;
} // end switch
} // end function __interrupt void USCI_B2_ISR(void)

//======================================================================//======================================================================
Mike Raines



Posted by c.li...@gmail.com April 15, 2014
Mike,

Are you sure you can use the TxBuffer() routine within an interrupt routine? I've had different problems when using debug output routines in interrupt routines. Mostly by blocking other interrupts firing (and missing data).
Posted by mrai...@hofferflow.com April 15, 2014
Hi Folks,

I am attempting to write/read a Microchip 24FC1025 eeprom using the intrinsic i2c on a Texas Instruments MSP430F5438A chip. This may be a mistake because I got no hits when searching the Microchip forum for msp430 or F5438. Has anyone done this successfully and, if so, what are the pitfalls to watch out for?

It is my understanding that this eeprom has two slave addresses, one for each half of the memory. The slave address for the lower half is 1010 000 (0x50) and for the upper half is 1010 100 (0x54). Before reading/writing the eeprom I must insure I'm using the proper slave address. This is an example of switching to block 1:
//====================================================================== //======================================================================
void InitializeUcb2Block1(void) // eeprom interface
{

UCB2CTL1 |= UCSWRST; // Enable SW reset
UCB2CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode
UCB2CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset
UCB2BR0 = 12; // fSCL = SMCLK/12 = ~100kHz
UCB2BR1 = 0;
UCB2I2CSA = 0x50; // Slave Address is 0x50 1010 000
UCB2CTL1 &= ~UCSWRST; // Clear SW reset, resume operation
UCB2IE |= UCTXIE; // Enable TX interrupt
UCB2IE |= UCRXIE; // enable rx interrupt

} // end function void InitializeUcb2ForI2cToEeprom(void)

//====================================================================== //======================================================================
// ================== ensure slave address points to block 1 =============
if (UCB2I2CSA != 0x50) // if not block 1
{
InitializeUcb2Block1();
} // end if not block 1

DelayMs(1); // test delay

This seems to work fine.

For writing, I first disable a write-protect pin P9.0 (set the pin low). I place the high and low bytes of the address into elements 0 and 1 of an array TxData, followed by the data bytes to place in the eeprom starting at this address. I then set a pointer used by the USCIB2 ISR (interrupt service routine) to the start of the array and another variable used by the isr, TXByteCtr, to the number of bytes to write. I then turn the process over to the intrinsic TI I2C by executing:
UCB2CTL1 |= UCTR + UCTXSTT; and while(UCB2CTL1 & UCTXSTP); The write-protect pin is enabled when the isr clocks out the last byte.

For reading, I disable the write-protect pin just to send the address and follow the write procedure placing just the read address in the array and setting TXByteCtr to 2. It is my understanding that the isr now sends the address and that this places the eeprom internal address pointer to the address I sent. I then set a pointer used by the isr to a buffer to receive the read bytes, and I set another variable available to the isr to the number of bytes to read. I then switch from write to read functionality by executing: UCB2CTL1 &= ~UCTR; and UCB2CTL1 |= UCTXSTT;

This seems to work most of the time, but I’m worried about several anomolies. Recently, I noticed that on a read, the isr only accesses every other byte. It's like the memory pointer is incrementing by 2 instead of 1. I discovered if I removed the three print statements from case 10 of the isr, the read worked normally.

Just yesterday, while implementing this to several write/read to/from eeprom instances, I removed the three “print” statements from case 12 of the isr because my PC printout was getting crowded. To my great surprise, the read operations stopped working. I put the statements back, and the read operations work again.

To summarize, it did not concern me greatly that the extra isr statements in case 10 caused read problems, and I had no heartburn about removing them. The (seeming) fact that the extra statements are necessary for case 12 to work is scary. I do not like working with algorithms that are this touchy.

Can someone please shed some light on this problem, and a possible solution? This is the isr:

//=========================================================== //=========================================================== #pragma vector = USCI_B2_VECTOR // TI intrinsic i2c isr
__interrupt void USCI_B2_ISR(void)
{
unsigned char iv = (unsigned char)UCB2IV;
// sprintf(outBuf, "UCB2IV is: %X", iv);
// TxBuffer(outBuf, 30, 1);

// switch(__even_in_range(UCB2IV,12))
switch(__even_in_range(iv,12))
{
case 0: break; // Vector 0: No interrupts
case 2: break; // Vector 2: ALIFG
case 4: break; // Vector 4: NACKIFG
case 6: break; // Vector 6: STTIFG
case 8: break; // Vector 8: STPIFG
case 10:

// TxBuffer("case 10:", 10, 1);
RXByteCtr --; // decrement rx byte counter
if (RXByteCtr) // if bytes to read
{
// sprintf(outBuf, "case 10:%X", UCB2RXBUF);
// TxBuffer(outBuf, 30, 1);
*PRxData ++ = UCB2RXBUF; // move data byte to buffer
if (RXByteCtr == 1) // if next-to-last byte
UCB2CTL1 |= UCTXSTP; // generate i2c stop condition
}
else
{
// sprintf(outBuf, "case 10:%X", UCB2RXBUF);
// TxBuffer(outBuf, 30, 1);
*PRxData = UCB2RXBUF; // move final byte to buffer
// __bic_SR_register_on_exit (LPM0_bits); // exit with active cpu
// __bic_SR_register_on_exit (LPM3_bits); // exit with active cpu
} // end if bytes to read else

break; // Vector 10: RXIFG
case 12: // Vector 12: TXIFG

TxBuffer("case 12: ", 12, 0);
if (TXByteCtr) // Check TX byte counter
{
sprintf(outBuf, "%X", *PTxData);
TxBuffer(outBuf, 30, 1);

UCB2TXBUF = *PTxData++; // Load TX buffer if bytes to send
TXByteCtr--; // Decrement TX byte counter
}
else
{
UCB2CTL1 |= UCTXSTP; // I2C stop condition
UCB2IFG &= ~UCTXIFG; // Clear USCI_B0 TX int flag
TxBuffer("***STOP***", 30, 1);
P9OUT |= BIT0; // write-protect on

// __bic_SR_register_on_exit(LPM0_bits); // Exit LPM0
// __bic_SR_register_on_exit(LPM3_bits); // Exit LPM3
} // end if bytes to send

break;
default: break;
} // end switch
} // end function __interrupt void USCI_B2_ISR(void)

//====================================================================== //======================================================================
Mike Raines