aboutsummaryrefslogtreecommitdiffstats
path: root/i2c.c
blob: a10141c20b083ff3c8d437bcbfffcc6031635256 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/*
 * i2c.h
 *
 *  Created on: 28 de abr de 2017
 *      Author: helio.capella
 *
 *      Based on msp430g2xx3_uscib0_i2c_12.c by D. Dang
 *
 *  Modified by tcsullivan:
 *      04/29: Modified pin macros to work with project
 */

#include <msp430.h>
#include "i2c.h"
#include "board.h"

#define I2CSEL   P1SEL
#define I2CSEL2  P1SEL2
#define I2CSCL   (TEMP_SCL)
#define I2CSDA   (TEMP_SDA)

void I2C_init(uint8_t slaveAddress){
    // Port Configuration
    I2CSEL |= I2CSDA + I2CSCL;                     // Assign I2C pins to USCI_B0
    I2CSEL2|= I2CSDA + I2CSCL;                     // Assign I2C pins to USCI_B0

//    isRx = 0;                                    // State variable - possibly useless

    //USCI Configuration
    UCB0CTL1 |= UCSWRST;                           // Enable SW reset
    UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC;          // I2C Master, synchronous mode
    UCB0CTL1 = UCSSEL_2 + UCSWRST;                 // Use SMCLK, keep SW reset

    //Set USCI Clock Speed
    UCB0BR0 = 12;                                  // fSCL = SMCLK/12 = ~100kHz
    UCB0BR1 = 0;

    //Set Slave Address and Resume operation
    UCB0I2CSA = slaveAddress;                      // Slave Address passed as parameter
    UCB0CTL1 &= ~UCSWRST;                          // Clear SW reset, resume operation
}


void I2C_write(uint8_t ByteCtr, uint8_t *TxData) {
    __disable_interrupt();
//    isRx = 0;
    //Interrupt management
    IE2 &= ~UCB0RXIE;                              // Disable RX interrupt
//    while (UCB0CTL1 & UCTXSTP);                  // Ensure stop condition got sent
    IE2 |= UCB0TXIE;                               // Enable TX interrupt

    //Pointer to where data is stored to be sent
    PTxData = (uint8_t *) TxData;                  // TX array start address
    TxByteCtr = ByteCtr;                           // Load TX byte counter

    //Send start condition
    //    while (UCB0CTL1 & UCTXSTP);              // Ensure stop condition got sent
    UCB0CTL1 |= UCTR + UCTXSTT;                    // I2C TX, start condition

    __bis_SR_register(CPUOFF + GIE);               // Enter LPM0 w/ interrupts
    while (UCB0CTL1 & UCTXSTP);
}

void I2C_read(uint8_t ByteCtr, volatile uint8_t *RxData) {
    __disable_interrupt();
//    isRx = 1;

    //Interrupt management
    IE2 &= ~UCB0TXIE;                              // Disable TX interrupt
    UCB0CTL1 = UCSSEL_2 + UCSWRST;                 // Use SMCLK, keep SW reset
    UCB0CTL1 &= ~UCSWRST;                          // Clear SW reset, resume operation
    IE2 |= UCB0RXIE;                               // Enable RX interrupt

    //Pointer to where data will be stored
    PRxData = (uint8_t *) RxData;                  // Start of RX buffer
    RxByteCtr = ByteCtr;                           // Load RX byte counter

    //while (UCB0CTL1 & UCTXSTP);                  // Ensure stop condition got sent

    //If only 1 byte will be read send stop signal as soon as it starts transmission
    if(RxByteCtr == 1){
        UCB0CTL1 |= UCTXSTT;                       // I2C start condition
        while (UCB0CTL1 & UCTXSTT);                // Start condition sent?
        UCB0CTL1 |= UCTXSTP;                       // I2C stop condition
        __enable_interrupt();
    } else {
        UCB0CTL1 |= UCTXSTT;                       // I2C start condition
    }

    __bis_SR_register(CPUOFF + GIE);               // Enter LPM0 w/ interrupts
    while (UCB0CTL1 & UCTXSTP);                    // Ensure stop condition got sent
}

#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector = USCIAB0TX_VECTOR
__interrupt void USCIAB0TX_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(USCIAB0TX_VECTOR))) USCIAB0TX_ISR (void)
#else
#error Compiler not supported!
#endif
{
  if(IFG2 & UCB0RXIFG){                              // Receive In
  if (RxByteCtr == 1)
  {
     *PRxData = UCB0RXBUF;                           // Move final RX data to PRxData
     __bic_SR_register_on_exit(CPUOFF);              // Exit LPM0
  }
  else
  {
      *PRxData++ = UCB0RXBUF;                        // Move RX data to address PRxData
      if (RxByteCtr == 2)                            // Check whether byte is second to last to be read to send stop condition
      UCB0CTL1 |= UCTXSTP;
      __no_operation();
  }
  RxByteCtr--;                                       // Decrement RX byte counter
  }

  else{                                              // Master Transmit
      if (TxByteCtr)                                 // Check TX byte counter
  {
    UCB0TXBUF = *PTxData;                            // Load TX buffer
    PTxData++;
    TxByteCtr--;                                     // Decrement TX byte counter
  }
  else
  {
    UCB0CTL1 |= UCTXSTP;                             // I2C stop condition
    IFG2 &= ~UCB0TXIFG;                              // Clear USCI_B0 TX int flag
    __bic_SR_register_on_exit(CPUOFF);               // Exit LPM0
  }
 }
}