Quantcast
Channel: MSP low-power microcontroller forum - Recent Threads
Viewing all articles
Browse latest Browse all 21942

CCS/MSP430F5529: I2C help on MSP430F5529

$
0
0

Part Number:MSP430F5529

Tool/software: Code Composer Studio

Team,

I  am a filed appications rotator working on getting a new sensor demo up and running for a customer. The sensor requires i2c and we are demoing on the MSP430F5529. Currently I am struggling just to get the i2c working so that I can write to and read from registers. I am not sure the sensor I am supposed to be demoing works correctly so currently I am just trying to read and write to/from a INA260 EVM over i2c. I have tried multiple approaches so far. I tried basing code off the USCIB0 read and write multiple bytes "examples". I also tried porting other peoples I2c code from other microcontrollers to the 5529 but have had little success. I believe my main issue is writing the ISR, I have found no good examples for this. 

Question #1:

Does TI have any good I2C examples for reading/writing to a device?

Question#2:

I included my 3 approaches below. If any of them seem close I would greatly appreciate your input on how I can get up and running with I2C. I have used I2C before on microchip controllers and have read all the TI literature I can find (User guide, datasheet, how to use I2C, basics of I2C, and mspware). I am also now familiar with the USCI library. 

Approach 1: wrote i2c based on the example code for the MSP430F2619.

main.c
#include <stdio.h>
#include <msp430f5529.h>
#include <lib5529i2c.h>

unsigned char array[5] = { 0x00, 0x07, 0x27};
unsigned char array2[5];
signed char byteCtr;
unsigned char *TI_receive_field;
unsigned char *TI_transmit_field;


void main(void)
{

    WDTCTL = WDTPW + WDTHOLD; // Disable Watchdog
    P1DIR |= 0x01;
    P1OUT= 0x00;// configure P1.0 as output
    _EINT(); // enable interrupts
    __enable_interrupt();
    TI_USCI_I2C_transmitinit(0x40, 0x12); // initialize USCI
    while ( TI_USCI_I2C_notready() );
    TI_USCI_I2C_transmit(3,array); // transmit the first 3 bytes of array
    //LPM0; // put CPU to sleep during communication
    TI_USCI_I2C_receiveinit(0x40,0x12);
    while ( TI_USCI_I2C_notready() );
    TI_USCI_I2C_receive(3,array2);
}

lib5529i2c.h

/*
 * lib5529i2c.h
 *
 *  Created on: Feb 9, 2018
 *      Author: a0226654
 */

#ifndef LIB5529I2C_H_
#define LIB5529I2C_H_

#define SDA_PIN BIT0                                  // msp430x261x UCB0SDA pin
#define SCL_PIN BIT1                                  // msp430x261x UCB0SCL pin



void TI_USCI_I2C_receiveinit(unsigned char slave_address, unsigned char prescale);
void TI_USCI_I2C_transmitinit(unsigned char slave_address, unsigned char prescale);


void TI_USCI_I2C_receive(unsigned char byteCount, unsigned char *field);
void TI_USCI_I2C_transmit(unsigned char byteCount, unsigned char *field);


unsigned char TI_USCI_I2C_slave_present(unsigned char slave_address);
unsigned char TI_USCI_I2C_notready();


#endif /* LIB5529I2C_H_ */





lib5529i2c.c

//******************************************************************************
//   MSP430 USCI I2C Transmitter and Receiver
//
//  Description: This code configures the MSP430's USCI module as
//  I2C master capable of transmitting and receiving bytes.
//
//  ***THIS IS THE MASTER CODE***
//
//                    Master
//                 MSP430F2619
//             -----------------
//         /|\|              XIN|-
//          | |                 |
//          --|RST          XOUT|-
//            |                 |
//            |                 |
//            |                 |
//            |         SDA/P3.1|------->
//            |         SCL/P3.2|------->
//
// Note: External pull-ups are needed for SDA & SCL
//
// Uli Kretzschmar
// Texas Instruments Deutschland GmbH
// November 2007
// Built with IAR Embedded Workbench Version: 3.42A
//******************************************************************************

#include "msp430f5529.h"                        // device specific header
//#include "msp430x22x4.h"
//#include "msp430x23x0.h"
//#include "msp430xG46x.h"
// ...                                         // more devices are possible

#include "lib5529i2c.h"

signed char byteCtr;
unsigned char *TI_receive_field;
unsigned char *TI_transmit_field;
int q=0;
//------------------------------------------------------------------------------
// void TI_USCI_I2C_receiveinit(unsigned char slave_address,
//                              unsigned char prescale)
//
// This function initializes the USCI module for master-receive operation.
//
// IN:   unsigned char slave_address   =>  Slave Address
//       unsigned char prescale        =>  SCL clock adjustment
//-----------------------------------------------------------------------------
void TI_USCI_I2C_receiveinit(unsigned char slave_address,
                             unsigned char prescale){
  P3SEL |= SDA_PIN + SCL_PIN;                 // 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 = prescale;                         // set prescaler
  UCB0BR1 = 0;
  UCB0I2CSA = slave_address;                  // set slave address
  UCB0CTL1 &= ~UCSWRST;                       // Clear SW reset, resume operation
  UCB0IE = UCNACKIE;
  UCB0IE = UCRXIE;                            // Enable RX interrupt
}

//------------------------------------------------------------------------------
// void TI_USCI_I2C_transmitinit(unsigned char slave_address,
//                               unsigned char prescale)
//
// This function initializes the USCI module for master-transmit operation.
//
// IN:   unsigned char slave_address   =>  Slave Address
//       unsigned char prescale        =>  SCL clock adjustment
//------------------------------------------------------------------------------
void TI_USCI_I2C_transmitinit(unsigned char slave_address,
                          unsigned char prescale){
  P3SEL |= SDA_PIN + SCL_PIN;                 // 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 = prescale;                         // set prescaler
  UCB0BR1 = 0;
  UCB0I2CSA = slave_address;                  // Set slave address
  UCB0CTL1 &= ~UCSWRST;                       // Clear SW reset, resume operation
  UCB0IE = UCNACKIE;
  UCB0IE |= UCTXIE;                            // Enable TX ready interrupt
}

//------------------------------------------------------------------------------
// void TI_USCI_I2C_receive(unsigned char byteCount, unsigned char *field)
//
// This function is used to start an I2C commuincation in master-receiver mode.
//
// IN:   unsigned char byteCount  =>  number of bytes that should be read
//       unsigned char *field     =>  array variable used to store received data
//------------------------------------------------------------------------------
void TI_USCI_I2C_receive(unsigned char byteCount, unsigned char *field){
  TI_receive_field = field;
  if ( byteCount == 1 ){
    byteCtr = 0 ;
    __disable_interrupt();
    UCB0CTL1 |= UCTXSTT;                      // I2C start condition
    while (UCB0CTL1 & UCTXSTT);               // Start condition sent?
    UCB0CTL1 |= UCTXSTP;                      // I2C stop condition
    __enable_interrupt();
  } else if ( byteCount > 1 ) {
    byteCtr = byteCount - 2 ;
    UCB0CTL1 |= UCTXSTT;                      // I2C start condition
  } else
    while (1);                                // illegal parameter
}

//------------------------------------------------------------------------------
// void TI_USCI_I2C_transmit(unsigned char byteCount, unsigned char *field)
//
// This function is used to start an I2C commuincation in master-transmit mode.
//
// IN:   unsigned char byteCount  =>  number of bytes that should be transmitted
//       unsigned char *field     =>  array variable. Its content will be sent.
//------------------------------------------------------------------------------
void TI_USCI_I2C_transmit(unsigned char byteCount, unsigned char *field){
  TI_transmit_field = field;
  byteCtr = byteCount;
  UCB0CTL1 |= UCTR + UCTXSTT;                 // I2C TX, start condition
}

//------------------------------------------------------------------------------
// unsigned char TI_USCI_I2C_slave_present(unsigned char slave_address)
//
// This function is used to look for a slave address on the I2C bus.
//
// IN:   unsigned char slave_address  =>  Slave Address
// OUT:  unsigned char                =>  0: address was not found,
//                                        1: address found
//------------------------------------------------------------------------------
unsigned char TI_USCI_I2C_slave_present(unsigned char slave_address){
  unsigned char ie2_bak, slaveadr_bak, ucb0i2cie, returnValue;
  ucb0i2cie = UCB0IE;                      // restore old UCB0I2CIE
  ie2_bak = UCB0IE;                              // store IE2 register
  slaveadr_bak = UCB0I2CSA;                   // store old slave address
  UCB0IE &= ~ UCNACKIE;                    // no NACK interrupt
  UCB0I2CSA = slave_address;                  // set slave address
  UCB0IE &= ~(UCTXIE + UCRXIE);              // no RX or TX interrupts
  __disable_interrupt();
  UCB0CTL1 |= UCTR + UCTXSTT + UCTXSTP;       // I2C TX, start condition
  while (UCB0CTL1 & UCTXSTP);                 // wait for STOP condition

  returnValue = !(UCB0STAT & UCNACKIFG);
  __enable_interrupt();
  UCB0IE = ie2_bak;                              // restore IE2
  UCB0I2CSA = slaveadr_bak;                   // restore old slave address
  UCB0IE = ucb0i2cie;                      // restore old UCB0CTL1
  return returnValue;                         // return whether or not
                                              // a NACK occured
}

//------------------------------------------------------------------------------
// unsigned char TI_USCI_I2C_notready()
//
// This function is used to check if there is commuincation in progress.
//
// OUT:  unsigned char  =>  0: I2C bus is idle,
//                          1: communication is in progress
//------------------------------------------------------------------------------
unsigned char TI_USCI_I2C_notready(){
  return (UCB0STAT & UCBBUSY);
}


#pragma vector = USCI_B0_VECTOR
__interrupt void USCI_B0_ISR(void)
{
    switch (__even_in_range(UCB0IV, 12))
        {

        case 10:
            q=10;// Vector 10: RXIFG -- I am not using it yet (but I'll need it)
            if (UCB0STAT & UCNACKIFG){            // send STOP if slave sends NACK
              UCB0CTL1 |= UCTXSTP;
              UCB0STAT &= ~UCNACKIFG;
            }
            break;
        case 12:
            q=12;// Vector 12: TXIFG
            if (P2IFG & UCRXIFG){
                    if ( byteCtr == 0 ){
                      UCB0CTL1 |= UCTXSTP;                    // I2C stop condition
                      *TI_receive_field = UCB0RXBUF;
                      TI_receive_field++;
                    }
                    else {
                      *TI_receive_field = UCB0RXBUF;
                      TI_receive_field++;
                      byteCtr--;
                    }
                  }
                  else {
                    if (byteCtr == 0){
                      UCB0CTL1 |= UCTXSTP;                    // I2C stop condition
                      P2IFG &= ~UCTXIFG;                     // Clear USCI_B0 TX int flag
                    }
                    else {
                      UCB0TXBUF = *TI_transmit_field;
                      TI_transmit_field++;
                      byteCtr--;
                    }
                  }
            break;
        default:
            break;

        }

    }

Approach 2: Wrote library based off 5529 read/write example code 

#include "msp430f5529.h"                        // device specific header
//#include "msp430x22x4.h"
//#include "msp430x23x0.h"
//#include "msp430xG46x.h"
// ...                                         // more devices are possible

#include "lib5529i2c.h"

signed char byteCtr;
unsigned char *TI_receive_field;
unsigned char *TI_transmit_field;
unsigned char TXByteCtr=0;
unsigned char RXByteCtr=0;

void TI_USCI_I2C_receiveinit(unsigned char slave_address,
                             unsigned char prescale){
  P3SEL |= SDA_PIN + SCL_PIN;                 // 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 = prescale;                         // set prescaler
  UCB0BR1 = 0;
  UCB0I2CSA = slave_address;                  // set slave address
  UCB0CTL1 &= ~UCSWRST;                       // Clear SW reset, resume operation
  UCB0IE = UCNACKIE;
  UCB0IE = UCRXIE;                            // Enable RX interrupt
}


void TI_USCI_I2C_transmitinit(unsigned char slave_address,
                          unsigned char prescale){
  P3SEL |= SDA_PIN + SCL_PIN;                 // 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 = prescale;                         // set prescaler
  UCB0BR1 = 0;
  UCB0I2CSA = slave_address;                  // Set slave address
  UCB0CTL1 &= ~UCSWRST;                       // Clear SW reset, resume operation
  UCB0IE = UCNACKIE;
  UCB0IE |= UCTXIE;                            // Enable TX ready interrupt
}


void TI_USCI_I2C_receive(unsigned char byteCount, unsigned char *field){
  TI_receive_field = field;
  if ( byteCount == 1 ){
    RXByteCtr = 0 ;
    __disable_interrupt();
    UCB0CTL1 |= UCTXSTT;                      // I2C start condition
    while (UCB0CTL1 & UCTXSTT);               // Start condition sent?
    UCB0CTL1 |= UCTXSTP;                      // I2C stop condition
    __enable_interrupt();
  } else if ( byteCount > 1 ) {
      RXByteCtr = byteCount - 2 ;
    UCB0CTL1 |= UCTXSTT;                      // I2C start condition
  } else
    while (1);                                // illegal parameter
}


void TI_USCI_I2C_transmit(unsigned char byteCount, unsigned char *field){
  TI_transmit_field = field;
  TXByteCtr = byteCount;
  UCB0CTL1 |= UCTR + UCTXSTT;                 // I2C TX, start condition
}


unsigned char TI_USCI_I2C_slave_present(unsigned char slave_address){
  unsigned char ie2_bak, slaveadr_bak, ucb0i2cie, returnValue;
  ucb0i2cie = UCB0IE;                      // restore old UCB0I2CIE
  ie2_bak = UCB0IE;                              // store IE2 register
  slaveadr_bak = UCB0I2CSA;                   // store old slave address
  UCB0IE &= ~ UCNACKIE;                    // no NACK interrupt
  UCB0I2CSA = slave_address;                  // set slave address
  UCB0IE &= ~(UCTXIE + UCRXIE);              // no RX or TX interrupts
  __disable_interrupt();
  UCB0CTL1 |= UCTR + UCTXSTT + UCTXSTP;       // I2C TX, start condition
  while (UCB0CTL1 & UCTXSTP);                 // wait for STOP condition

  returnValue = !(UCB0STAT & UCNACKIFG);
  __enable_interrupt();
  UCB0IE = ie2_bak;                              // restore IE2
  UCB0I2CSA = slaveadr_bak;                   // restore old slave address
  UCB0IE = ucb0i2cie;                      // restore old UCB0CTL1
  return returnValue;                         // return whether or not
                                              // a NACK occured
}


unsigned char TI_USCI_I2C_notready(){
  return (UCB0STAT & UCBBUSY);
}


#pragma vector = USCI_B0_VECTOR
__interrupt void USCI_B0_ISR(void)
{
    switch (__even_in_range(UCB0IV, 12))
        {

        case 10:
            
            RXByteCtr--;                            // Decrement RX byte counter
                if (RXByteCtr)
                {
                    *TI_receive_field = UCB0RXBUF;               // Move RX data to address PRxData
                  if (RXByteCtr == 1)                   // Only one byte left?
                    UCB0CTL1 |= UCTXSTP;                // Generate I2C stop condition
                }
                else
                {
                    *TI_receive_field = UCB0RXBUF;                 // Move final RX data to PRxData
                  __bic_SR_register_on_exit(LPM0_bits); // Exit active CPU
                }
            
        case 12:
            
            if (TXByteCtr)                          // Check TX byte counter
               {
                 UCB0TXBUF = *TI_transmit_field;               // Load TX buffer
                 TXByteCtr--;                          // Decrement TX byte counter
               }
               else
               {
                 UCB0CTL1 |= UCTXSTP;                  // I2C stop condition
                 UCB0IFG &= ~UCTXIFG;                  // Clear USCI_B0 TX int flag
                 __bic_SR_register_on_exit(LPM0_bits); // Exit LPM0
               }
            
        default:
            break;

        }

    }

/*
* Here's an example using an MSP430G2553 to read/write using I2C to an 24LC512 and DS3231 RTC.
* Two functions are provided for read and write.
*
* The code avoids any while loops, and relies completely on interrupts and low power modes of the MSP430 to reduce the power consumption to the
* minimum.
*
* Author: Ahmed Talaat (aa_talaat@yahoo.com)
* Date: 19 October 2012
*/

    #include  "msp430f5529.h"

    #define ONEBYTEADDR 1
    #define TWOBYTEADDR 2
    #define WRITE       0                       // ISR mode WRITE or READ
    #define READ        1
    #define NOACK       2
    #define EEPROM_ADDR 0x40
    #define DS3231_ADDR 0x00

    unsigned char txdataEEPROM[2];
    unsigned char txdataDS3231[7] = {0x20, 0x30, 0x20, 0x04, 0x17, 0x10, 0x12};
    unsigned char rxdata[150];

    typedef struct {
        volatile unsigned char *data_buf;       // address of tx or rx data buffer
        volatile unsigned char buf_size;        // size of the buffer
        volatile unsigned char buf_index;       // index in the buffer
        volatile unsigned char addr_index;      // index of the byte address (0,1)
        volatile unsigned char isr_mode;        // Tx or Rx affects the interrupt logic
        volatile unsigned char addr_high_byte;  // High byte of the address to read/write to
        volatile unsigned char addr_low_byte;   // Low byte of the address to read/write to
        volatile unsigned char addr_type;       // two bytes like eeprom or 1 byte like RTC for example
    } i2c_t;

    i2c_t   i2c_packet;

    void i2c_init(void);
    void i2c_tx(unsigned char, unsigned char *, unsigned char, unsigned char, unsigned char, unsigned char);
    void i2c_rx(unsigned char, unsigned char *, unsigned char, unsigned char, unsigned char, unsigned char);
    void usdelay(int);

    void main(void)
    {
       WDTCTL = WDTPW + WDTHOLD;                // Stop WDT
       i2c_init();                              // Initialize I2C
       txdataEEPROM[0]=0x61;
       txdataEEPROM[1]=0x3F;

       i2c_tx(EEPROM_ADDR, txdataEEPROM, sizeof(txdataEEPROM)-1,ONEBYTEADDR,0x00,0x00);//i2c TX 115 bytes starting @ address 01:00

       i2c_rx(EEPROM_ADDR, rxdata, 2,ONEBYTEADDR,0x00,0x00);//i2c RX 115 bytes from EEPROM starting @ address 01:00
  

       LPM0;                                    // Enter LPM0 w/ interrupts
    }

    void i2c_init(void){
        P3SEL |= BIT0 + BIT1;                   //Set I2C pins
        //P1SEL2|= BIT6 + BIT7;
        UCB0CTL1 |= UCSWRST;                    //Enable SW reset
        UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC;   //I2C Master, synchronous mode
        UCB0CTL1 = UCSSEL_2 + UCSWRST;          //Use SMCLK, keep SW reset
        UCB0BR0 = 10;                           //fSCL = SMCLK/11 = ~100kHz
        UCB0BR1 = 0;
        UCB0CTL1 &= ~UCSWRST;                   //Clear SW reset, resume operation
        UCB0IE |= UCTXIE;                        //Enable TX interrupt
        UCB0IE |= UCRXIE;                        //Enable RX interrupt
        UCB0IE |= UCNACKIE;                  //Need to enable the status change interrupt
        __enable_interrupt();                   //Enable global interrupt
    }


    void i2c_tx(unsigned char slave_addr, unsigned char *txdata, unsigned char bufSize, unsigned char addr_size,
                        unsigned char high_byte_addr, unsigned char low_byte_addr) {
        i2c_packet.isr_mode=WRITE;
        i2c_packet.data_buf=txdata;
        i2c_packet.buf_size=bufSize;
        i2c_packet.buf_index=0;
        i2c_packet.addr_type=addr_size;
        i2c_packet.addr_high_byte=high_byte_addr;
        i2c_packet.addr_low_byte=low_byte_addr;
        i2c_packet.addr_index=0;
        UCB0I2CSA = slave_addr;                 //Slave Address

        while (1) {
            UCB0CTL1 |= UCTR + UCTXSTT;         // I2C TX, start condition
            LPM0;                               // Enter LPM0
                                                // and remain until all data is TX'd
            if (i2c_packet.isr_mode == NOACK){  // If no ack received, then sleep for 0.5ms and try again
                i2c_packet.isr_mode = WRITE;
                i2c_packet.addr_index=0;        // Reset the address index for the next write operation
                usdelay(500);

            } else {
                break;                          // Successful write, then quit
            }
        }
    }

    /*
     * This functions reads from any I2C device. It takes as parameters:
     *  - The slave address (7 bits)
     *  - Pointer to the data buffer to fill with data read.
     *  - Size of the buffer
     *  - Size of the address location to start writing at. Being 2 bytes for some of the EEPROMs and single byte
     *    for other devices. Please note that the ISR of this function assumes that the address bytes are written high
     *    byte first, then low byte second.
     *    In case of single byte address device, only the high byte will be used to set the address.
     *  - The high byte and low byte address for the location to start reading at.
     *
     *  The function starts with a write operation to specify the address at which the read operation with start
     *  In case the start condition of the write operation is not ack (for example EEPROM busy with a a previous write cycle),
     *  the corresponding interrupts detects this condition, generates a stop signal, and a Timer A1 (not Timer A0)
     *  is activated for 0.5 ms, then the trial for writing is repeated.
     *
     *  Once the write address is successful, the functions switch to read mode, and fills the buffer provided
     *
     */


    void i2c_rx(unsigned char slave_addr, unsigned char *rxdata, unsigned char bufSize, unsigned char addr_size,
            unsigned char high_byte_addr, unsigned char low_byte_addr) {
        i2c_packet.isr_mode=READ;               // The ISR will send the address bytes, then wake CPU.
        i2c_packet.addr_type=addr_size;
        i2c_packet.addr_high_byte=high_byte_addr;
        i2c_packet.addr_low_byte=low_byte_addr;
        i2c_packet.addr_index=0;
        UCB0I2CSA = slave_addr;                 // Slave Address

        while (1) {
            UCB0CTL1 |= UCTR + UCTXSTT;         // I2C TX, start condition
            LPM0;                               // Enter LPM0
                                                // and remain until all data is TX'd
            if (i2c_packet.isr_mode == NOACK){  // If no ack received, then sleep for 0.5ms and try again
                i2c_packet.isr_mode = READ;
                i2c_packet.addr_index=0;        // Reset the address index for the next write operation
                usdelay(500);
            } else {
                break;                          // Successful write, then quit
            }
        }
                                                // We wrote already the address, so now read only data.
        i2c_packet.addr_index=i2c_packet.addr_type;
        i2c_packet.data_buf=rxdata;
        i2c_packet.buf_size=bufSize;
        i2c_packet.buf_index=0;
        UCB0CTL1 &= ~UCTR;                      // I2C RX
        UCB0CTL1 |= UCTXSTT;                    // I2C re-start condition
        LPM0;                                   // Enter LPM0
                                                // and remain until all data is received
    }


    //interrupt(USCIAB0RX_VECTOR) state change to trap the no_Ack from slave case

/*
 * This interrupt is called each time the UCSI_B module is either ready to get a new byte in UCB0TXBUF to send to the I2C device, or
 * a new byte is read into UCB0RXBUF and we should pick it up.
 * The interrupt is called as both UCB0TXIE and UCB0RXIE are enabled. To stop this interrupt being called indefinitely, the corresponding
 * interrupt flag should be cleared.
 * These flags are automatically clearly by the USCI_B module if the UCB0XXBUF is access. However, if we are to do something different than reading
 * or writing a byte to/from the UCB0XXBUF, we need to clear the corresponding flag by ourselves or the ISR will be called for ever,
 * and the whole program will hang.
 */


#pragma vector = USCI_B0_VECTOR
__interrupt void USCI_B0_ISR(void)
{
    switch (__even_in_range(UCB0IV, 12))
        {
        case 10:
            RXByteCtr--;                            // Decrement RX byte counter
                if (RXByteCtr)
                {
                  *PRxData++ = UCB0RXBUF;               // Move RX data to address PRxData
                  if (RXByteCtr == 1)                   // Only one byte left?
                    UCB0CTL1 |= UCTXSTP;                // Generate I2C stop condition
                }
                else
                {
                  *PRxData = UCB0RXBUF;                 // Move final RX data to PRxData
                  __bic_SR_register_on_exit(LPM0_bits); // Exit active CPU
                }
        case 12:
            // Transmit address bytes irrespective of send or receive mode.*/
                    if (i2c_packet.addr_index==0){
                       UCB0TXBUF = i2c_packet.addr_high_byte;
                       i2c_packet.addr_index++;
                    }
                    else if (i2c_packet.addr_index==1 && i2c_packet.addr_type==TWOBYTEADDR){
                        UCB0TXBUF = i2c_packet.addr_low_byte;
                        i2c_packet.addr_index++;
                    }
                    else if(UCTXIFG & P2IFG && i2c_packet.isr_mode==READ) {
                                                            // USCI_B is ready to get a new data byte to transmit it, and we are in READ mode.
                                                            // So, we should not continue writing, but should exit to the calling function to
                                                            // switch the USCI_B into read mode
                        P2IFG &= ~UCTXIFG;                 // Clear USCI_B0 TX int flag manually as we did not write to the UCB0TXBUF
                        LPM0_EXIT;                          // Exit LPM0
                    }

                    else if(UCTXIFG & P2IFG && i2c_packet.isr_mode==WRITE){// USCI_B is ready to get a new data byte to transmit it, and we are in write mode.

                        if(i2c_packet.buf_index == i2c_packet.buf_size){    // If no more data to transmit, then issue stop condition and wake CPU.
                            P2IFG &= ~UCTXIFG;                             // Clear USCI_B0 TX int flag manually as we did not write to the UCB0TXBUF
                            UCB0CTL1 |= UCTXSTP;                            // I2C stop condition
                            LPM0_EXIT;                                      // Exit LPM0
                        } else {
                            UCB0TXBUF = i2c_packet.data_buf[i2c_packet.buf_index];
                            i2c_packet.buf_index++;                         // Increment TX byte counter
                        }
                   }
                    else if (UCRXIFG & P2IFG && i2c_packet.addr_index==i2c_packet.addr_type) {
                                                                            // Read mode, and we already completed writing the address
                    i2c_packet.data_buf[i2c_packet.buf_index]= UCB0RXBUF;
                    i2c_packet.buf_index++;                             // Increment RX byte counter
                    if(i2c_packet.buf_index == i2c_packet.buf_size){    // If last byte to receive, then issue stop condition and wake CPU.
                        P2IFG &= ~UCRXIFG;                             // Clear USCI_B0 RX int flag
                        UCB0CTL1 |= UCTXSTP;                            // I2C stop condition here to avoid reading any extra bytes
                        LPM0_EXIT;                                      // Exit LPM0
                    }
                }
/*
            break;
        default:
            break;
*/
        }

    }




    //------------------------------------------------------------------------------
    // micro seconds delays
    //
    void usdelay(int interval){
                                    // Setup TimerA
        TA1CCTL0 = CCIE;            // interrupt enabled
        TA1CCR0 = TA1R + interval;  // micro secs @ 1Mhz Clock
        TA1CTL = TASSEL_2 + MC_2;   // SMCLK, continuous mode.
        LPM0;                       // suspend CPU
    }

    // Timer A1 interrupt service routine. TIMERx_Ay_VECTOR.(x being the index of the timer, y of the vector for this timer)
    #pragma vector=TIMER1_A0_VECTOR
    __interrupt void Timer1_A0 (void)
    {
        TA1CTL = 0;                     // Stop Timer_A1
        LPM0_EXIT;                      // Return active
    }

//******************************************************************************//   MSP430 USCI I2C Transmitter and Receiver////  Description: This code configures the MSP430's USCI module as//  I2C master capable of transmitting and receiving bytes.////  ***THIS IS THE MASTER CODE***////                    Master//                 MSP430F2619//             -----------------//         /|\|              XIN|-//          | |                 |//          --|RST          XOUT|-//            |                 |//            |                 |//            |                 |//            |         SDA/P3.1|------->//            |         SCL/P3.2|------->//// Note: External pull-ups are needed for SDA & SCL//// Uli Kretzschmar// Texas Instruments Deutschland GmbH// November 2007// Built with IAR Embedded Workbench Version: 3.42A//******************************************************************************/*#include "msp430f5529.h"                        // device specific header//#include "msp430x22x4.h"//#include "msp430x23x0.h"//#include "msp430xG46x.h"// ...                                         // more devices are possible
#include "lib5529i2c.h"
signed char byteCtr;unsigned char *TI_receive_field;unsigned char *TI_transmit_field;int q=0;//------------------------------------------------------------------------------// void TI_USCI_I2C_receiveinit(unsigned char slave_address,//                              unsigned char prescale)//// This function initializes the USCI module for master-receive operation.//// IN:   unsigned char slave_address   =>  Slave Address//       unsigned char prescale        =>  SCL clock adjustment//-----------------------------------------------------------------------------void TI_USCI_I2C_receiveinit(unsigned char slave_address,                             unsigned char prescale){  P3SEL |= SDA_PIN + SCL_PIN;                 // 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 = prescale;                         // set prescaler  UCB0BR1 = 0;  UCB0I2CSA = slave_address;                  // set slave address  UCB0CTL1 &= ~UCSWRST;                       // Clear SW reset, resume operation  UCB0IE = UCNACKIE;  UCB0IE = UCRXIE;                            // Enable RX interrupt}
//------------------------------------------------------------------------------// void TI_USCI_I2C_transmitinit(unsigned char slave_address,//                               unsigned char prescale)//// This function initializes the USCI module for master-transmit operation.//// IN:   unsigned char slave_address   =>  Slave Address//       unsigned char prescale        =>  SCL clock adjustment//------------------------------------------------------------------------------void TI_USCI_I2C_transmitinit(unsigned char slave_address,                          unsigned char prescale){  P3SEL |= SDA_PIN + SCL_PIN;                 // 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 = prescale;                         // set prescaler  UCB0BR1 = 0;  UCB0I2CSA = slave_address;                  // Set slave address  UCB0CTL1 &= ~UCSWRST;                       // Clear SW reset, resume operation  UCB0IE = UCNACKIE;  UCB0IE |= UCTXIE;                            // Enable TX ready interrupt}
//------------------------------------------------------------------------------// void TI_USCI_I2C_receive(unsigned char byteCount, unsigned char *field)//// This function is used to start an I2C commuincation in master-receiver mode.//// IN:   unsigned char byteCount  =>  number of bytes that should be read//       unsigned char *field     =>  array variable used to store received data//------------------------------------------------------------------------------void TI_USCI_I2C_receive(unsigned char byteCount, unsigned char *field){  TI_receive_field = field;  if ( byteCount == 1 ){    byteCtr = 0 ;    __disable_interrupt();    UCB0CTL1 |= UCTXSTT;                      // I2C start condition    while (UCB0CTL1 & UCTXSTT);               // Start condition sent?    UCB0CTL1 |= UCTXSTP;                      // I2C stop condition    __enable_interrupt();  } else if ( byteCount > 1 ) {    byteCtr = byteCount - 2 ;    UCB0CTL1 |= UCTXSTT;                      // I2C start condition  } else    while (1);                                // illegal parameter}
//------------------------------------------------------------------------------// void TI_USCI_I2C_transmit(unsigned char byteCount, unsigned char *field)//// This function is used to start an I2C commuincation in master-transmit mode.//// IN:   unsigned char byteCount  =>  number of bytes that should be transmitted//       unsigned char *field     =>  array variable. Its content will be sent.//------------------------------------------------------------------------------void TI_USCI_I2C_transmit(unsigned char byteCount, unsigned char *field){  TI_transmit_field = field;  byteCtr = byteCount;  UCB0CTL1 |= UCTR + UCTXSTT;                 // I2C TX, start condition}
//------------------------------------------------------------------------------// unsigned char TI_USCI_I2C_slave_present(unsigned char slave_address)//// This function is used to look for a slave address on the I2C bus.//// IN:   unsigned char slave_address  =>  Slave Address// OUT:  unsigned char                =>  0: address was not found,//                                        1: address found//------------------------------------------------------------------------------unsigned char TI_USCI_I2C_slave_present(unsigned char slave_address){  unsigned char ie2_bak, slaveadr_bak, ucb0i2cie, returnValue;  ucb0i2cie = UCB0IE;                      // restore old UCB0I2CIE  ie2_bak = UCB0IE;                              // store IE2 register  slaveadr_bak = UCB0I2CSA;                   // store old slave address  UCB0IE &= ~ UCNACKIE;                    // no NACK interrupt  UCB0I2CSA = slave_address;                  // set slave address  UCB0IE &= ~(UCTXIE + UCRXIE);              // no RX or TX interrupts  __disable_interrupt();  UCB0CTL1 |= UCTR + UCTXSTT + UCTXSTP;       // I2C TX, start condition  while (UCB0CTL1 & UCTXSTP);                 // wait for STOP condition
  returnValue = !(UCB0STAT & UCNACKIFG);  __enable_interrupt();  UCB0IE = ie2_bak;                              // restore IE2  UCB0I2CSA = slaveadr_bak;                   // restore old slave address  UCB0IE = ucb0i2cie;                      // restore old UCB0CTL1  return returnValue;                         // return whether or not                                              // a NACK occured}
//------------------------------------------------------------------------------// unsigned char TI_USCI_I2C_notready()//// This function is used to check if there is commuincation in progress.//// OUT:  unsigned char  =>  0: I2C bus is idle,//                          1: communication is in progress//------------------------------------------------------------------------------unsigned char TI_USCI_I2C_notready(){  return (UCB0STAT & UCBBUSY);}

#pragma vector = USCI_B0_VECTOR__interrupt void USCI_B0_ISR(void){    switch (__even_in_range(UCB0IV, 12))        {
        case 10:            q=10;// Vector 10: RXIFG -- I am not using it yet (but I'll need it)            if (UCB0STAT & UCNACKIFG){            // send STOP if slave sends NACK              UCB0CTL1 |= UCTXSTP;              UCB0STAT &= ~UCNACKIFG;            }            break;        case 12:            q=12;// Vector 12: TXIFG            if (P2IFG & UCRXIFG){                    if ( byteCtr == 0 ){                      UCB0CTL1 |= UCTXSTP;                    // I2C stop condition                      *TI_receive_field = UCB0RXBUF;                      TI_receive_field++;                    }                    else {                      *TI_receive_field = UCB0RXBUF;                      TI_receive_field++;                      byteCtr--;                    }                  }                  else {                    if (byteCtr == 0){                      UCB0CTL1 |= UCTXSTP;                    // I2C stop condition                      P2IFG &= ~UCTXIFG;                     // Clear USCI_B0 TX int flag                    }                    else {                      UCB0TXBUF = *TI_transmit_field;                      TI_transmit_field++;                      byteCtr--;                    }                  }            break;        default:            break;
        }
    }

*/


Viewing all articles
Browse latest Browse all 21942

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>