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.
CIDE: Code Composer v4.2.1
MICROCONTROLLER: MSP430F5438
SENSOR: Honeywell HMC6343 (Digital Compass)
GOAL: To interface the MSP430F5438 to the HMC6343 using I2C.
Upon sending a start condition, slave address (32), and R/W bit (0), we receive a NACK from the slave. We are running out of ideas for solving this issue.... We wrote our own code from scratch and sampled TI's code with no success.
Currently we are trying to get an AK bit from the slave using TI's sample code below....but we always get a NACK. Why doesn't this work?!?!?!?
Also, see oscilloscope plot and circuit diagram below.
Any help is much appreciated :)
//******************************************************************************
// MSP430F54x Demo - USCI_B0 I2C Master TX single bytes to MSP430 Slave
//
// Description: This demo connects two MSP430's via the I2C bus. The master
// transmits to the slave. This is the master code. It continuously
// transmits 00h, 01h, ..., 0ffh and demonstrates how to implement an I2C
// master transmitter sending a single byte using the USCI_B0 TX interrupt.
// ACLK = n/a, MCLK = SMCLK = BRCLK = default DCO = ~1.045MHz
//
// /|\ /|\
// MSP430F5438 10k 10k MSP430F5438
// slave | | master
// ----------------- | | -----------------
// -|XIN P3.1/UCB0SDA|<-|----+->|P3.1/UCB0SDA XIN|-
// | | | | |
// -|XOUT | | | XOUT|-
// | P3.2/UCB0SCL|<-+------>|P3.2/UCB0SCL |
// | | | |
//
// M Smertneck / W. Goh
// Texas Instruments Inc.
// September 2008
// Built with CCE Version: 3.2.2 and IAR Embedded Workbench Version: 4.11B
//******************************************************************************
#include "msp430x54x.h"
unsigned char TXData;
unsigned char TXByteCtr;
void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop WDT
P3SEL |= 0x06; // Assign I2C pins to USCI_B0
UCB0CTL1 |= UCSWRST; // Enable SW reset
UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode
UCB0CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset
UCB0BR0 = 12; // fSCL = SMCLK/12 = ~100kHz
UCB0BR1 = 0;
UCB0I2CSA = 0x32; // Slave Address is 032h
UCB0CTL1 &= ~UCSWRST; // Clear SW reset, resume operation
UCB0IE |= UCTXIE; // Enable TX interrupt
TXData = 0x01; // Holds TX data
while (1)
{
TXByteCtr = 1; // Load TX byte counter
while (UCB0CTL1 & UCTXSTP); // Ensure stop condition got sent
UCB0CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition
__bis_SR_register(LPM0_bits + GIE); // Enter LPM0 w/ interrupts
__no_operation(); // Remain in LPM0 until all data
// is TX'd
TXData++; // Increment data byte
}
}
//------------------------------------------------------------------------------
// The USCIAB0_ISR is structured such that it can be used to transmit any
// number of bytes by pre-loading TXByteCtr with the byte count.
//------------------------------------------------------------------------------
#pragma vector = USCI_B0_VECTOR
__interrupt void USCI_B0_ISR(void)
{
switch(__even_in_range(UCB0IV,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: break; // Vector 10: RXIFG
case 12: // Vector 12: TXIFG
if (TXByteCtr) // Check TX byte counter
{
UCB0TXBUF = TXData;
UCB0IE &= ~UCTXIE; // Load TX buffer
TXByteCtr--; // Decrement TX byte counter
}
else
{
UCB0CTL1 |= UCTXSTP; // I2C stop condition
UCB0IFG &= ~UCTXIFG; // Clear USCI_B0 TX int flag
UCB0IE &= ~UCTXIE;
__bic_SR_register_on_exit(LPM0_bits); // Exit LPM0
}
break;
default: break;
}
}
Hi Nick,
I'm not sure this post will be helpful for you, but please take a look at http://electronix.ru/forum/lofiversion/index.php/t70411.html
This is a russian forum, the same problem with HMC5843 (also a I2C compass) is described here. In brief (if you're not familiar with russian :) ) :
1)The author doesn't want to use interrupts.
2)He say that he has NACK on 9th clock while writing to HMC.
3)The solution for him was to write:
...
UCB0CTL1 |= UCTXSTT | UCTR; // Send START, SLAVE ADDR with WRITE
... (see the source)
instead of
...
UCB0CTL1 |= UCTXSTT | UCTR; // Send START, SLAVE ADDR with WRITE
while (UCB0CTL1 & UCTXSTT); //<-- THIS LINE IS WRONG
...
He provides working source:
#define NACK_TX -1
#define NACK_RX -2
int I2C_Read(unsigned char addr, unsigned char *data, int cnt){
int result,i;
result = 0;
UCB0CTL1 |= UCTXSTT | UCTR; // Send START, SLAVE ADDR with WRITE
// while (UCB0CTL1 & UCTXSTT);
while (!(IFG2 & UCB0TXIFG)) if (UCB0STAT & UCNACKIFG){
result = NACK_TX;
goto STOP;
}
UCB0TXBUF = addr;
while (!(IFG2 & UCB0TXIFG)) if (UCB0STAT & UCNACKIFG){
result = NACK_TX;
goto STOP;
}
UCB0CTL1 &= ~UCTR;
UCB0CTL1 |= UCTXSTT; // Send START, SLAVE ADDR with WRITE
for (i=0;i<cnt;i++){
while (!(IFG2 & UCB0RXIFG)) if (UCB0STAT & UCNACKIFG){
result = NACK_RX;
goto STOP;
}
data[i] = UCB0RXBUF;
}//for
STOP:
UCB0CTL1 |= UCTXSTP;
while (UCB0CTL1 & UCTXSTP); // Ensure stop condition got sent
if (IFG2 & UCB0RXIFG) UCB0RXBUF;
return result;
}//I2C_Read
As I'm unfamiliar with HMCxxxx, I can't say exactly that this solution is acceptable for you, but take a look at it.
Regards,
Ilia V. Davidov
First, why are ~95% of all tags you have selected totally unrelated to your problem? Did you just check every tag you could find? It might get you more attention by putting you on everyones list, but rather decreases the chance that anyone scanning the tags will answer.
Now to your problem: I'm surprised by your scope reading: the idle state of the clock line should be high and not low.
Is it 48h (=0x48) or is it 0x64? And if it is0c64, is it really 0x62 or is it rather 0x32? The slave address does not contain the R/W bit. This is added from the UCTR bit when sending the start sequence. Note that thsi bit is added physically as 8th bit to the 7 bit address and not just numerically added to an 8 bit address.Nick Gentry said:UCB0I2CSA = 0x64; // Slave Address is 048h
This combinations makes no sense. Either you wait for the start sequence to be clear or you enter LPM and let the ISRs handle everything.Nick Gentry said:UCB0CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition
__bis_SR_register(LPM0_bits + GIE); // Enter LPM0 w/ interrupts
This disables teh interrupt rather than clearing the interrupt flag (whcih has been already cleared by the previous write to TXBUF. Once the interrupt is disabled, you won't enter the ISR anymore. THis also means that after pushing the first byte into TXBUF, no more bytes are pushed, no end of the transfer is detected and therefore the LPM is never exited.Nick Gentry said:UCB0IE &= ~UCTXIE; // Load TX buffer
Thank you for your replies! :)
Jens: I have have modified the tags, thanks for your input. Regarding the slave address, it is supposed to be 32h. I was doing some testing and forgot to change the code back to 32h (0b110010) before posting.
I am still looking over your comments and doing some experimenting. Will send update soon.
Hi Jens,
To clarify, we did set the slave address to be 32h in the slave address register as shown in the oscilloscope plot. I'm slightly confused about the addition of the R/W bit. The line, UCB0CTL1 |= UCTR + UCTXSTT; does it for us, doesn't it? The idle state of the clock being high is something I completely missed and can't explain why it's inverted. We changed the pull up values to 1 KOhm from 10 KOhm to get a better signal for the clock. With the 10 Kohm pull ups, the clock looked more like a capacitor charging and discharging (o-scope plot was taken using 10K pullups). Do you think this is ok? I'll check for the UCNACKIFG too, should i do this by enabling the interrupt for a NACK?
I have a few more questions as well. The MSP430F5438 goes into a transmit interrupt after the start condition is sent and after I load the TXBUF with data, the program just lives in the interrupt and never leaves it. I don't know what we should do about that. Also, when I step through the line UCB0CTL1 |= UCTR + UCTXSTT, I watch the UCB0CTL1 and the UCTXSTT bit is never set. Is this supposed to happen? Do you know what's wrong? We'd greatly appreciate your input.
Also, to debug, I just sent a repeated start condition without enabling interrupts or doing anything else. The slave never sends back an ACK. Also, thanks for pointing out the sleep mode condition (I've never implemented it before). I'm just not going to use it for now. So, would just executing _EINT() before the beginning of the loop be sufficient and then we could ignore that entire line altogether?
Thanks,
Nick
Any idea why the clock signal seems to be inverted? We are using 10Kohm pullup resistors to the +3.3V line. How is this possible? See oscilloscope plot above.
Thanks!!
It isn't inverted. The protocol allows data changes only during low clock signal (except for start/stop condition). And this is what happens. All data changes happen at/after the falling edge of the clock, and only the start/stop happens after the rising edge/on high level. That's okay. It's only during the idle time where the clock should be high but isn't.Nick Gentry said:Any idea why the clock signal seems to be inverted?
I am trying to do the same but my code is not working. Can you please guide me with some help.
**Attention** This is a public forum