Skip to content

Instantly share code, notes, and snippets.

@ossicode
Created January 2, 2013 13:59
Show Gist options
  • Save ossicode/4434782 to your computer and use it in GitHub Desktop.
Save ossicode/4434782 to your computer and use it in GitHub Desktop.
temporary i2c master and slave all together. master mode is still working
/*
* i2c.c
*
* Created on: 2012. 12. 30.
* Author: OSSI
*/
// we implement I2C as below:
//
// 7 bit addressing mode
// NO Multi-Master
#include "i2c.h"
// Master
// max buffer size
#define I2C_RX_BUFFER_SIZE 16
#define I2C_TX_BUFFER_SIZE 16
static uint16_t i2cRXIndex;
static uint16_t i2cTXIndex;
static uint8_t *rxData;
static uint8_t *txData;
// Slave
static uint16_t slaveRXIndex;
static uint16_t slaveTXIndex;
static uint8_t *slaveRXData;
static uint8_t *slaveTXData;
static uint8_t i2cTxFlag;
static uint8_t i2cRxFlag;
void i2c_setTxFlag(void)
{
i2cTxFlag = 1;
}
void i2c_clearTxFlag(void)
{
i2cTxFlag = 0;
}
uint8_t i2c_getTxFlag(void)
{
return i2cTxFlag;
}
void i2c_setRxFlag(void)
{
i2cRxFlag = 1;
}
void i2c_clearRxFlag(void)
{
i2cRxFlag = 0;
}
uint8_t i2c_getRxFlag(void)
{
return i2cRxFlag;
}
void i2c_portSetup(void)
{
// For MSP430F2132, P3.1 = SDA, P3.2 = SCL
P3SEL |= 0x06;
}
// call this only when you need need master
void i2c_masterInit(uint8_t selctClockSource, uint16_t preScalerValue ,uint8_t modeSelect)
{
ASSERT((selctClockSource == I2C_CLOCKSOURCE_ACLK)||(selctClockSource == I2C_CLOCKSOURCE_SMCLK));
ASSERT((preScalerValue>=4) && (preScalerValue<=0xFFFF));
ASSERT((modeSelect == I2C_TRANSMIT_MODE)||(modeSelect == I2C_RECEIVE_MODE));
// reset I2C
UCB0CTL1 = UCSWRST;
// reset and set UCB0CTL0 for I2C mode
// UCA10 = 0 owe address 7 bit
// UCSLA10 = 0 slave address 7bit
// UCMM = 0 no multi-master
UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC;
// reset clock source while UCSWRST = 1
UCB0CTL1 = selctClockSource + modeSelect + UCSWRST;
// fSCL = selctClockSource / preScalerValue
// for single master mode, minimum preScalerValue = 4
UCB0BR0 = preScalerValue & 0xFF;
UCB0BR1 = (preScalerValue >> 8) & 0xFF;
UCB0CTL1 &= ~UCSWRST;
}
void i2c_setSlaveAddress(uint8_t slaveAddress)
{
// slaveAddress is right justified. bit 6 is MSB for 7 bit address
// TODO:how to check whether we have valid 7 bit slaveAddress?
UCB0I2CSA = slaveAddress;
}
void i2c_enableRXInterrupt(void)
{
IE2 |= UCB0RXIE;
}
void i2c_disableRXInterrupt(void)
{
IE2 &= ~UCB0RXIE;
}
void i2c_enableTXInterrupt(void)
{
IE2 |= UCB0TXIE;
}
void i2c_disableTXInterrupt(void)
{
IE2 &= ~UCB0TXIE;
}
void i2c_masterReceive(uint8_t byteCount, uint8_t *data)
{
ASSERT((byteCount >=1)&&(byteCount<=I2C_RX_BUFFER_SIZE));
rxData = data;
if (byteCount == 1)
{
i2cRXIndex = byteCount ;
__disable_interrupt();
UCB0CTL1 |= UCTXSTT; // I2C start condition
while (UCB0CTL1 & UCTXSTT); // Start condition sent?
UCB0CTL1 |= UCTXSTP; // I2C stop condition
__enable_interrupt();
}
else if (byteCount > 1)
{
i2cRXIndex = byteCount ;
UCB0CTL1 |= UCTXSTT; // I2C start condition
}
}
void i2c_masterSend(uint8_t byteCount, uint8_t *data)
{
ASSERT((byteCount >=1)&&(byteCount<=I2C_TX_BUFFER_SIZE));
txData = data;
i2cTXIndex = byteCount;
UCB0CTL1 |= UCTXSTT; // I2C TX, start condition
}
void i2c_slaveInit(uint8_t rxByteCount, uint8_t *rxData, uint8_t txByteCount, uint8_t *txData)
{
// initialize buffer and count
slaveRXData = rxData;
slaveTXData = txData;
slaveRXIndex = rxByteCount;
slaveTXIndex = txByteCount;
UCB0CTL1 |= UCSWRST; // Enable SW reset
UCB0CTL0 = UCMODE_3 + UCSYNC; // I2C Slave, synchronous mode
UCB0CTL1 &= ~UCSWRST; // Clear SW reset, resume operation
IE2 |= UCB0TXIE + UCB0RXIE; // Enable TX interrupt
UCB0I2CIE |= UCSTTIE; // Enable STT interrupt
}
void i2c_setOwnAddress(uint8_t slaveAddress)
{
UCB0I2COA = slaveAddress;
}
#pragma vector = USCIAB0RX_VECTOR
__interrupt void USCIAB0RX_ISR(void)
{
// Master & Slave Mode: when NACK is detected
if (UCB0STAT & UCNACKIFG){ // send STOP if slave sends NACK
UCB0CTL1 |= UCTXSTP;
UCB0STAT &= ~UCNACKIFG;
// i2c_disableRXInterrupt();
// TA0CCTL0 |= CCIE;
// __bic_SR_register_on_exit(LPM3_bits);
}
// Slave mode: when start condition is detected
if (UCB0STAT & UCSTTIFG)
{
UCB0STAT &= ~UCSTTIFG; // Clear start condition int flag
// initialize something
// TI_start_callback();
}
}
#pragma vector = USCIAB0TX_VECTOR
__interrupt void USCIAB0TX_ISR(void)
{
// uart interrupt
if ((IFG2 & UCA0TXIFG) && (IE2 & UCA0TXIE))
{
IE2 &= ~UCA0TXIE;
}
// i2c RX interrupt
if (IFG2 & UCB0RXIFG)
{
// Master
if (UCB0CTL0 & UCMST)
{
//easier when we count down and compare for the one last byte to initiate STOP condition
i2cRXIndex--;
if (i2cRXIndex)
{
*rxData = UCB0RXBUF;
rxData++;
if (i2cRXIndex == 1)
{
UCB0CTL1 |= UCTXSTP;
}
}
else
{
*rxData = UCB0RXBUF;
// when all bytes we want are received
// TODO: make separate process for the below
// i2c_disableRXInterrupt();
// TA0CCTL0 |= CCIE;
// Back to Low Power Mode
__bic_SR_register_on_exit(LPM3_bits);
}
}
else
{
// Slave
if(slaveRXIndex)
{
*slaveRXData = UCB0RXBUF;
slaveRXData++;
slaveRXIndex --;
}
else
{
// when we receive all data
}
}
}
// i2c TX interrupt
if (IFG2 & UCB0TXIFG)
{
// Master
if (UCB0CTL0 & UCMST)
{
//easier when we count down and compare for the one last byte to initiate STOP condition
if (i2cTXIndex)
{
UCB0TXBUF=*txData;
txData++;
// When we send only one byte, do this after sending one byte
i2cTXIndex--;
}
else
{
// When we send only one byte, do this after sending one byte
UCB0CTL1 |= UCTXSTP; // Generate I2C stop condition right after sending last data
IFG2 &= ~UCB0TXIFG;
// send last byte
// UCB0TXBUF=*txData;
// i2c_disableTXInterrupt();
// TA0CCTL0 |= CCIE;
// Back to Low Power Mode
// __bic_SR_register_on_exit(LPM3_bits);
}
}
else
{
// Slave
if (slaveTXIndex)
{
UCB0TXBUF = *slaveTXData;
slaveTXData++;
slaveTXIndex --;
}
else
{
// when we transmit all the data
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment