EmbeddedRelated.com
Forums
Memfault Beyond the Launch

MSP430F5338 I2C communication

Started by Songsongsong August 28, 2012
Hi group,

I have to receive data from slave sensor(LSM303DLM:Accelerometer) by I2C. However I don't know well how I make code of trasmit & receive.

Here is my code of I2C register setting. But I don't know how to approach next of this code. I just want to transmit slave address, register address and data. And then receive data from slave sensor continuously. There are many example codes in online, but I cannot understand them... Please let me know example codes or some diretions.. Thank you.
void SetI2C (void)
{
UCB0CTL1 |= UCSWRST; // **Put state machine in reset**
UCB0CTL0 |= UCMST | UCSYNC | UCMODE_3;
// Master mode, 7 bit address,I2C mode

UCB0CTL1 |= UCSSEL_2; // SMCLK
UCB0BR0 = 0x04; // /4 --- 2.304 MHz
UCB0BR1 = 0;
UCB0I2CSA = ACC_ADDRESS_W;
UCB0CTL1 &= ~UCSWRST; // **Initialize USCI state machine**
UCB0IE = UCNACKIE;
}

Beginning Microcontrollers with the MSP430

#include

unsigned int RxByteCtr;
unsigned int RxWord;

void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop WDT
P1DIR |= 0x01; // P1.0 output
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 = 0x21; // Set slave address
UCB0CTL1 &= ~UCSWRST; // Clear SW reset, resume
operation
IE2 |= UCB0RXIE; // Enable RX interrupt
TACTL = TASSEL_2 + MC_2; // SMCLK, contmode

while (1)
{
RxByteCtr = 2; // Load RX byte counter
UCB0CTL1 |= UCTXSTT; // I2C start condition
__bis_SR_register(CPUOFF + GIE); // Enter LPM0, enable
interrupts
// Remain in LPM0 until all
data
// is RX'd
if (RxWord > 200)
P1OUT |= 0x01;
else
P1OUT &= ~0x01;

__disable_interrupt();
TACCTL0 |= CCIE; // TACCR0 interrupt enabled
__bis_SR_register(CPUOFF + GIE); // Enter LPM0, enable
interrupts
// Remain in LPM0 until
TACCR0
// interrupt occurs
TACCTL0 &= ~CCIE; // TACCR0 interrupt disabled
}
}

#pragma vector = TIMERA0_VECTOR
__interrupt void TA0_ISR(void)
{
__bic_SR_register_on_exit(CPUOFF); // Exit LPM0
}

// The USCIAB0TX_ISR is structured such that it can be used to receive
any
// 2+ number of bytes by pre-loading RxByteCtr with the byte count.
#pragma vector = USCIAB0TX_VECTOR
__interrupt void USCIAB0TX_ISR(void)
{
RxByteCtr--; // Decrement RX byte counter

if (RxByteCtr)
{
RxWord = (unsigned int)UCB0RXBUF << 8; // Get received byte
if (RxByteCtr == 1) // Only one byte left?
UCB0CTL1 |= UCTXSTP; // Generate I2C stop
condition
}
else
{
RxWord |= UCB0RXBUF; // Get final received byte,
// Combine MSB and LSB
__bic_SR_register_on_exit(CPUOFF); // Exit LPM0
}
}
Essentially, you send a command to your slave device using an address
and then wait for the response from the slave device. In order to do
this, you must setup timers, control registers, the I2c protocol, etc as
done in the the main loop. This is setup in Master sync mode so that
one device (the master) can control many other devices (slaves). The
slave address used in this example is UCB0I2CSA = 0x21. So once
everything is setup, it's time to actually use the I2c protocol.
UCB0CTL1 |= UCTXSTT; will start the i2c by calling the slave address
stored in UCB0I2CSA. Now it's up to the slave to recognize that it is
being called and send the appropriate response. The accelerometer will
layout what needs to be sent to it to whatever data you need (x, y, or z
axis measurements) . This program will remain in lpm until data is
received. Once everything is received, then a stop condition is set.

To really understand how to use your micro, checkout the TI datasheet.
It will go through each thing in detail and tell you exactly what
registers to set. It really is the only way to learn this stuff.

--- In m..., "Songsongsong" wrote:
>
> Hi group,
>
> I have to receive data from slave sensor(LSM303DLM:Accelerometer) by
I2C. However I don't know well how I make code of trasmit & receive.
>
> Here is my code of I2C register setting. But I don't know how to
approach next of this code. I just want to transmit slave address,
register address and data. And then receive data from slave sensor
continuously. There are many example codes in online, but I cannot
understand them... Please let me know example codes or some diretions..
Thank you.
> void SetI2C (void)
> {
> UCB0CTL1 |= UCSWRST; // **Put state machine in reset**
> UCB0CTL0 |= UCMST | UCSYNC | UCMODE_3;
> // Master mode, 7 bit address,I2C mode
>
> UCB0CTL1 |= UCSSEL_2; // SMCLK
> UCB0BR0 = 0x04; // /4 --- 2.304 MHz
> UCB0BR1 = 0;
> UCB0I2CSA = ACC_ADDRESS_W;
> UCB0CTL1 &= ~UCSWRST; // **Initialize USCI state machine**
> UCB0IE = UCNACKIE;
> }
>

I really appreciate your help.

And I have one question about register UCB0I2CSA.

If I attend to receive data from my slave sensor, the operation protocol is like this.

MASTER : ST SAD+W SUB SR SAD+R MAK....
SLAVE : SAK SAK SAK DATA .......

I think master should send SAD+W, SUB and SAD+R before slave send DATA. But I don't know the function of UCB0I2CSA.
If I assign slave's address SAD+W to UCB0I2CSA, sending SAD+W to slave(UCB0TXBUF = SAD+W) is not needed? Should I just use UCTXSTT and send SUB, SAD+R?
Render it down, I wonder to know when I to do something through I2C, UCB0I2CSA is sent automatically to slave??

Thank you.
--- In m..., "gymb321" wrote:
>
> #include unsigned int RxByteCtr;
> unsigned int RxWord;
>
> void main(void)
> {
> WDTCTL = WDTPW + WDTHOLD; // Stop WDT
> P1DIR |= 0x01; // P1.0 output
> 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 = 0x21; // Set slave address
> UCB0CTL1 &= ~UCSWRST; // Clear SW reset, resume
> operation
> IE2 |= UCB0RXIE; // Enable RX interrupt
> TACTL = TASSEL_2 + MC_2; // SMCLK, contmode
>
> while (1)
> {
> RxByteCtr = 2; // Load RX byte counter
> UCB0CTL1 |= UCTXSTT; // I2C start condition
> __bis_SR_register(CPUOFF + GIE); // Enter LPM0, enable
> interrupts
> // Remain in LPM0 until all
> data
> // is RX'd
> if (RxWord > 200)
> P1OUT |= 0x01;
> else
> P1OUT &= ~0x01;
>
> __disable_interrupt();
> TACCTL0 |= CCIE; // TACCR0 interrupt enabled
> __bis_SR_register(CPUOFF + GIE); // Enter LPM0, enable
> interrupts
> // Remain in LPM0 until
> TACCR0
> // interrupt occurs
> TACCTL0 &= ~CCIE; // TACCR0 interrupt disabled
> }
> }
>
> #pragma vector = TIMERA0_VECTOR
> __interrupt void TA0_ISR(void)
> {
> __bic_SR_register_on_exit(CPUOFF); // Exit LPM0
> }
>
> // The USCIAB0TX_ISR is structured such that it can be used to receive
> any
> // 2+ number of bytes by pre-loading RxByteCtr with the byte count.
> #pragma vector = USCIAB0TX_VECTOR
> __interrupt void USCIAB0TX_ISR(void)
> {
> RxByteCtr--; // Decrement RX byte counter
>
> if (RxByteCtr)
> {
> RxWord = (unsigned int)UCB0RXBUF << 8; // Get received byte
> if (RxByteCtr == 1) // Only one byte left?
> UCB0CTL1 |= UCTXSTP; // Generate I2C stop
> condition
> }
> else
> {
> RxWord |= UCB0RXBUF; // Get final received byte,
> // Combine MSB and LSB
> __bic_SR_register_on_exit(CPUOFF); // Exit LPM0
> }
> }
> Essentially, you send a command to your slave device using an address
> and then wait for the response from the slave device. In order to do
> this, you must setup timers, control registers, the I2c protocol, etc as
> done in the the main loop. This is setup in Master sync mode so that
> one device (the master) can control many other devices (slaves). The
> slave address used in this example is UCB0I2CSA = 0x21. So once
> everything is setup, it's time to actually use the I2c protocol.
> UCB0CTL1 |= UCTXSTT; will start the i2c by calling the slave address
> stored in UCB0I2CSA. Now it's up to the slave to recognize that it is
> being called and send the appropriate response. The accelerometer will
> layout what needs to be sent to it to whatever data you need (x, y, or z
> axis measurements) . This program will remain in lpm until data is
> received. Once everything is received, then a stop condition is set.
>
> To really understand how to use your micro, checkout the TI datasheet.
> It will go through each thing in detail and tell you exactly what
> registers to set. It really is the only way to learn this stuff.
>
> --- In m..., "Songsongsong" wrote:
> >
> > Hi group,
> >
> > I have to receive data from slave sensor(LSM303DLM:Accelerometer) by
> I2C. However I don't know well how I make code of trasmit & receive.
> >
> > Here is my code of I2C register setting. But I don't know how to
> approach next of this code. I just want to transmit slave address,
> register address and data. And then receive data from slave sensor
> continuously. There are many example codes in online, but I cannot
> understand them... Please let me know example codes or some diretions..
> Thank you.
> >
> >
> > void SetI2C (void)
> > {
> > UCB0CTL1 |= UCSWRST; // **Put state machine in reset**
> > UCB0CTL0 |= UCMST | UCSYNC | UCMODE_3;
> > // Master mode, 7 bit address,I2C mode
> >
> > UCB0CTL1 |= UCSSEL_2; // SMCLK
> > UCB0BR0 = 0x04; // /4 --- 2.304 MHz
> > UCB0BR1 = 0;
> > UCB0I2CSA = ACC_ADDRESS_W;
> > UCB0CTL1 &= ~UCSWRST; // **Initialize USCI state machine**
> > UCB0IE = UCNACKIE;
> > }
>


Memfault Beyond the Launch