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.
使用官方例程 msp430g2xx3_usci_i2c_standard_slave.c 代码 板子为官方 msp-exp430g2 时 无响应,连I2C起始 中断都不进入,测量P1.6 P1.7电压波形一切正常!有人用过MSP430 硬件I2C从机模式吗?之前试过MSP430F5438A,使用官方例程也没成功.附上官方例程代码
//******************************************************************************
// MSP430G2xx3 Demo - USCI_B0, I2C Slave multiple byte TX/RX
//
// Description: I2C master communicates to I2C slave sending and receiving
// 3 different messages of different length. (This is the slave code). The
// slave will be in LPM0 mode, waiting for the master to initiate the
// communication. The slave will send/receive bytes based on the master's
// request. The slave will handle I2C bytes sent/received using the
// I2C interrupt.
// ACLK = NA, MCLK = SMCLK = DCO 16MHz.
//
//
// MSP430G2553 3.3V
// ----------------- /|\ /|\
// /|\ | | | 4.7k
// | | | 4.7k |
// ---|RST | | |
// | | | |
// | P1.6|---|---+- I2C Clock (UCB0SCL)
// | | |
// | P1.7|---+----- I2C Data (UCB0SDA)
// | |
// | |
//
// Nima Eskandari
// Texas Instruments Inc.
// April 2017
// Built with CCS V7.0
//******************************************************************************
#include <msp430.h>
#include <stdint.h>
//******************************************************************************
// Example Commands ************************************************************
//******************************************************************************
#define SLAVE_ADDR 0x48
/* CMD_TYPE_X_SLAVE are example commands the master sends to the slave.
* The slave will send example SlaveTypeX buffers in response.
*
* CMD_TYPE_X_MASTER are example commands the master sends to the slave.
* The slave will initialize itself to receive MasterTypeX example buffers.
* */
#define CMD_TYPE_0_SLAVE 0
#define CMD_TYPE_1_SLAVE 1
#define CMD_TYPE_2_SLAVE 2
#define CMD_TYPE_0_MASTER 3
#define CMD_TYPE_1_MASTER 4
#define CMD_TYPE_2_MASTER 5
#define TYPE_0_LENGTH 1
#define TYPE_1_LENGTH 2
#define TYPE_2_LENGTH 6
#define MAX_BUFFER_SIZE 20
/* MasterTypeX are example buffers initialized in the master, they will be
* sent by the master to the slave.
* SlaveTypeX are example buffers initialized in the slave, they will be
* sent by the slave to the master.
* */
uint8_t MasterType2 [TYPE_2_LENGTH] = {0};
uint8_t MasterType1 [TYPE_1_LENGTH] = { 0, 0};
uint8_t MasterType0 [TYPE_0_LENGTH] = { 0};
uint8_t SlaveType2 [TYPE_2_LENGTH] = {'A', 'B', 'C', 'D', '1', '2'};
uint8_t SlaveType1 [TYPE_1_LENGTH] = {15, 16};
uint8_t SlaveType0 [TYPE_0_LENGTH] = {12};
//******************************************************************************
// General I2C State Machine ***************************************************
//******************************************************************************
typedef enum I2C_ModeEnum{
IDLE_MODE,
NACK_MODE,
TX_REG_ADDRESS_MODE,
RX_REG_ADDRESS_MODE,
TX_DATA_MODE,
RX_DATA_MODE,
SWITCH_TO_RX_MODE,
SWITHC_TO_TX_MODE,
TIMEOUT_MODE
} I2C_Mode;
/* Used to track the state of the software state machine*/
I2C_Mode SlaveMode = RX_REG_ADDRESS_MODE;
/* The Register Address/Command to use*/
uint8_t ReceiveRegAddr = 0;
/* ReceiveBuffer: Buffer used to receive data in the ISR
* RXByteCtr: Number of bytes left to receive
* ReceiveIndex: The index of the next byte to be received in ReceiveBuffer
* TransmitBuffer: Buffer used to transmit data in the ISR
* TXByteCtr: Number of bytes left to transfer
* TransmitIndex: The index of the next byte to be transmitted in TransmitBuffer
* */
uint8_t ReceiveBuffer[MAX_BUFFER_SIZE] = {0};
uint8_t RXByteCtr = 0;
uint8_t ReceiveIndex = 0;
uint8_t TransmitBuffer[MAX_BUFFER_SIZE] = {0};
uint8_t TXByteCtr = 0;
uint8_t TransmitIndex = 0;
/* Initialized the software state machine according to the received cmd
*
* cmd: The command/register address received
* */
void I2C_Slave_ProcessCMD(uint8_t cmd);
/* The transaction between the slave and master is completed. Uses cmd
* to do post transaction operations. (Place data from ReceiveBuffer
* to the corresponding buffer based in the last received cmd)
*
* cmd: The command/register address corresponding to the completed
* transaction
*/
void I2C_Slave_TransactionDone(uint8_t cmd);
void CopyArray(uint8_t *source, uint8_t *dest, uint8_t count);
void I2C_Slave_ProcessCMD(uint8_t cmd)
{
ReceiveIndex = 0;
TransmitIndex = 0;
RXByteCtr = 0;
TXByteCtr = 0;
switch (cmd)
{
case (CMD_TYPE_0_SLAVE): //Send slave device id (This device's id)
SlaveMode = TX_DATA_MODE;
TXByteCtr = TYPE_0_LENGTH;
//Fill out the TransmitBuffer
CopyArray(SlaveType0, TransmitBuffer, TYPE_0_LENGTH);
IE2 &= ~UCB0RXIE; // Disable RX interrupt
IE2 |= UCB0TXIE; // Enable TX interrupt
break;
case (CMD_TYPE_1_SLAVE): //Send slave device time (This device's time)
SlaveMode = TX_DATA_MODE;
TXByteCtr = TYPE_1_LENGTH;
//Fill out the TransmitBuffer
CopyArray(SlaveType1, TransmitBuffer, TYPE_1_LENGTH);
IE2 &= ~UCB0RXIE; // Disable RX interrupt
IE2 |= UCB0TXIE; // Enable TX interrupt
break;
case (CMD_TYPE_2_SLAVE): //Send slave device location (This device's location)
SlaveMode = TX_DATA_MODE;
TXByteCtr = TYPE_2_LENGTH;
//Fill out the TransmitBuffer
CopyArray(SlaveType2, TransmitBuffer, TYPE_2_LENGTH);
IE2 &= ~UCB0RXIE; // Disable RX interrupt
IE2 |= UCB0TXIE; // Enable TX interrupt
break;
case (CMD_TYPE_0_MASTER):
SlaveMode = RX_DATA_MODE;
RXByteCtr = TYPE_0_LENGTH;
IE2 &= ~UCB0TXIE; // Disable RX interrupt
IE2 |= UCB0RXIE; // Enable TX interrupt
break;
case (CMD_TYPE_1_MASTER):
SlaveMode = RX_DATA_MODE;
RXByteCtr = TYPE_1_LENGTH;
IE2 &= ~UCB0TXIE; // Disable RX interrupt
IE2 |= UCB0RXIE; // Enable TX interrupt
break;
case (CMD_TYPE_2_MASTER):
SlaveMode = RX_DATA_MODE;
RXByteCtr = TYPE_2_LENGTH;
IE2 &= ~UCB0TXIE; // Disable RX interrupt
IE2 |= UCB0RXIE; // Enable TX interrupt
break;
default:
__no_operation();
break;
}
}
void I2C_Slave_TransactionDone(uint8_t cmd)
{
switch (cmd)
{
case (CMD_TYPE_0_SLAVE): //Slave device id was sent(This device's id)
break;
case (CMD_TYPE_1_SLAVE): //Slave device time was sent(This device's time)
break;
case (CMD_TYPE_2_SLAVE): //Send slave device location (This device's location)
break;
case (CMD_TYPE_0_MASTER):
CopyArray(ReceiveBuffer, MasterType0, TYPE_0_LENGTH);
break;
case (CMD_TYPE_1_MASTER):
CopyArray(ReceiveBuffer, MasterType1, TYPE_1_LENGTH);
break;
case (CMD_TYPE_2_MASTER):
CopyArray(ReceiveBuffer, MasterType2, TYPE_2_LENGTH);
break;
default:
__no_operation();
break;
}
}
void CopyArray(uint8_t *source, uint8_t *dest, uint8_t count)
{
uint8_t copyIndex = 0;
for (copyIndex = 0; copyIndex < count; copyIndex++)
{
dest[copyIndex] = source[copyIndex];
}
}
//******************************************************************************
// Device Initialization *******************************************************
//******************************************************************************
void initClockTo16MHz()
{
if (CALBC1_16MHZ==0xFF) // If calibration constant erased
{
while(1); // do not load, trap CPU!!
}
DCOCTL = 0; // Select lowest DCOx and MODx settings
BCSCTL1 = CALBC1_16MHZ; // Set DCO
DCOCTL = CALDCO_16MHZ;
}
void initGPIO()
{
P1SEL |= BIT6 + BIT7; // Assign I2C pins to USCI_B0
P1SEL2|= BIT6 + BIT7; // Assign I2C pins to USCI_B0
}
void initI2C()
{
UCB0CTL1 |= UCSWRST; // Enable SW reset
UCB0CTL0 = UCMODE_3 + UCSYNC; // I2C Slave, synchronous mode
UCB0I2COA = SLAVE_ADDR; // Own Address
UCB0CTL1 &= ~UCSWRST; // Clear SW reset, resume operation
UCB0I2CIE |= UCSTPIE + UCSTTIE; // Enable STT and STP interrupt
IE2 |= UCB0RXIE; // Enable RX interrupt
}
//******************************************************************************
// Main ************************************************************************
// Enters LPM0 and waits for I2C interrupts. The data sent from the master is *
// then interpreted and the device will respond accordingly *
//******************************************************************************
int main(void) {
WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer
initClockTo16MHz();
initGPIO();
initI2C();
__bis_SR_register(LPM0_bits + GIE);
return 0;
}
//******************************************************************************
// I2C Interrupt For Received and Transmitted Data******************************
//******************************************************************************
#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 Data Interrupt
{
//Must read from UCB0RXBUF
uint8_t rx_val = UCB0RXBUF;
switch (SlaveMode)
{
case (RX_REG_ADDRESS_MODE):
ReceiveRegAddr = rx_val;
I2C_Slave_ProcessCMD(ReceiveRegAddr);
break;
case (RX_DATA_MODE):
ReceiveBuffer[ReceiveIndex++] = rx_val;
RXByteCtr--;
if (RXByteCtr == 0)
{
//Done Receiving MSG
SlaveMode = RX_REG_ADDRESS_MODE;
IE2 &= ~(UCB0TXIE);
IE2 |= UCB0RXIE; // Enable RX interrupt
I2C_Slave_TransactionDone(ReceiveRegAddr);
}
break;
default:
__no_operation();
break;
}
}
else if (IFG2 & UCB0TXIFG) // Transmit Data Interrupt
{
//Must write to UCB0TXBUF
switch (SlaveMode)
{
case (TX_DATA_MODE):
UCB0TXBUF = TransmitBuffer[TransmitIndex++];
TXByteCtr--;
if (TXByteCtr == 0)
{
//Done Transmitting MSG
SlaveMode = RX_REG_ADDRESS_MODE;
IE2 &= ~(UCB0TXIE);
IE2 |= UCB0RXIE; // Enable RX interrupt
I2C_Slave_TransactionDone(ReceiveRegAddr);
}
break;
default:
__no_operation();
break;
}
}
}
//******************************************************************************
// I2C Interrupt For Start, Restart, Nack, Stop ********************************
//******************************************************************************
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector = USCIAB0RX_VECTOR
__interrupt void USCIAB0RX_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(USCIAB0RX_VECTOR))) USCIAB0RX_ISR (void)
#else
#error Compiler not supported!
#endif
{
//仿真挂断点连这里都跳不进来
if (UCB0STAT & UCSTPIFG) //Stop or NACK Interrupt
{
UCB0STAT &=
~(UCSTTIFG + UCSTPIFG + UCNACKIFG); //Clear START/STOP/NACK Flags
}
if (UCB0STAT & UCSTTIFG)
{
UCB0STAT &= ~(UCSTTIFG); //Clear START Flags
}
}
下面我附上的文件中,主从有两种通信方式。
g2553_i2c_slave.c 设备正在等待主设备与其通信。然后它将执行 6 个命令之一。
fr5529_i2c_master.c 设备将发送三个消息,并要求读取三个消息。消息长度不同。
使用的引脚是 fr5529 上的 P2.0 和 P2.1。MSP430G2553 上的 P1.6 和 P1.7。
它们都将以 16 MHz 运行。使用的 I2C 上拉电阻是 10k 欧姆电阻。
#include <msp430.h> #include <stdint.h> #include <stdbool.h> #define SLAVE_ADDR 0x48 #define CMD_TYPE_0_SLAVE 0 #define CMD_TYPE_1_SLAVE 1 #define CMD_TYPE_2_SLAVE 2 #define CMD_TYPE_0_MASTER 3 #define CMD_TYPE_1_MASTER 4 #define CMD_TYPE_2_MASTER 5 #define TYPE_0_LENGTH 1 #define TYPE_1_LENGTH 2 #define TYPE_2_LENGTH 6 #define MAX_BUFFER_SIZE 20 typedef enum I2C_ModeEnum{ IDLE_MODE, NACK_MODE, TX_REG_ADDRESS_MODE, RX_REG_ADDRESS_MODE, TX_DATA_MODE, RX_DATA_MODE, SWITCH_TO_RX_MODE, SWITHC_TO_TX_MODE, TIMEOUT_MODE } I2C_Mode; uint8_t MasterType2 [TYPE_2_LENGTH] = {'F', '4', '1', '9', '2', 'B'}; uint8_t MasterType1 [TYPE_1_LENGTH] = { 8, 9}; uint8_t MasterType0 [TYPE_0_LENGTH] = { 11}; uint8_t SlaveType2 [TYPE_2_LENGTH] = {0}; uint8_t SlaveType1 [TYPE_1_LENGTH] = {0}; uint8_t SlaveType0 [TYPE_0_LENGTH] = {0}; I2C_Mode MasterMode = IDLE_MODE; uint8_t TransmitRegAddr = 0; uint8_t ReceiveBuffer[MAX_BUFFER_SIZE] = {0}; uint8_t RXByteCtr = 0; uint8_t ReceiveIndex = 0; uint8_t TransmitBuffer[MAX_BUFFER_SIZE] = {0}; uint8_t TXByteCtr = 0; uint8_t TransmitIndex = 0; /* I2C Write and Read Functions */ I2C_Mode I2C_Master_WriteReg(uint8_t dev_addr, uint8_t reg_addr, uint8_t *reg_data, uint8_t count); I2C_Mode I2C_Master_ReadReg(uint8_t dev_addr, uint8_t reg_addr, uint8_t count); void CopyArray(uint8_t *source, uint8_t *dest, uint8_t count); void initClockTo16MHz() { UCSCTL3 |= SELREF_2; // Set DCO FLL reference = REFO UCSCTL4 |= SELA_2; // Set ACLK = REFO __bis_SR_register(SCG0); // Disable the FLL control loop UCSCTL0 = 0x0000; // Set lowest possible DCOx, MODx UCSCTL1 = DCORSEL_5; // Select DCO range 16MHz operation UCSCTL2 = FLLD_0 + 487; // Set DCO Multiplier for 16MHz // (N + 1) * FLLRef = Fdco // (487 + 1) * 32768 = 16MHz // Set FLL Div = fDCOCLK __bic_SR_register(SCG0); // Enable the FLL control loop // Worst-case settling time for the DCO when the DCO range bits have been // changed is n x 32 x 32 x f_MCLK / f_FLL_reference. See UCS chapter in 5xx // UG for optimization. // 32 x 32 x 16 MHz / 32,768 Hz = 500000 = MCLK cycles for DCO to settle __delay_cycles(500000);// // Loop until XT1,XT2 & DCO fault flag is cleared do { UCSCTL7 &= ~(XT2OFFG + XT1LFOFFG + DCOFFG); // Clear XT2,XT1,DCO fault flags SFRIFG1 &= ~OFIFG; // Clear fault flags }while (SFRIFG1&OFIFG); // Test oscillator fault flag } uint16_t setVCoreUp(uint8_t level){ uint32_t PMMRIE_backup, SVSMHCTL_backup, SVSMLCTL_backup; //The code flow for increasing the Vcore has been altered to work around //the erratum FLASH37. //Please refer to the Errata sheet to know if a specific device is affected //DO NOT ALTER THIS FUNCTION //Open PMM registers for write access PMMCTL0_H = 0xA5; //Disable dedicated Interrupts //Backup all registers PMMRIE_backup = PMMRIE; PMMRIE &= ~(SVMHVLRPE | SVSHPE | SVMLVLRPE | SVSLPE | SVMHVLRIE | SVMHIE | SVSMHDLYIE | SVMLVLRIE | SVMLIE | SVSMLDLYIE ); SVSMHCTL_backup = SVSMHCTL; SVSMLCTL_backup = SVSMLCTL; //Clear flags PMMIFG = 0; //Set SVM highside to new level and check if a VCore increase is possible SVSMHCTL = SVMHE | SVSHE | (SVSMHRRL0 * level); //Wait until SVM highside is settled while((PMMIFG & SVSMHDLYIFG) == 0) { ; } //Clear flag PMMIFG &= ~SVSMHDLYIFG; //Check if a VCore increase is possible if((PMMIFG & SVMHIFG) == SVMHIFG) { //-> Vcc is too low for a Vcore increase //recover the previous settings PMMIFG &= ~SVSMHDLYIFG; SVSMHCTL = SVSMHCTL_backup; //Wait until SVM highside is settled while((PMMIFG & SVSMHDLYIFG) == 0) { ; } //Clear all Flags PMMIFG &= ~(SVMHVLRIFG | SVMHIFG | SVSMHDLYIFG | SVMLVLRIFG | SVMLIFG | SVSMLDLYIFG ); //Restore PMM interrupt enable register PMMRIE = PMMRIE_backup; //Lock PMM registers for write access PMMCTL0_H = 0x00; //return: voltage not set return false; } //Set also SVS highside to new level //Vcc is high enough for a Vcore increase SVSMHCTL |= (SVSHRVL0 * level); //Wait until SVM highside is settled while((PMMIFG & SVSMHDLYIFG) == 0) { ; } //Clear flag PMMIFG &= ~SVSMHDLYIFG; //Set VCore to new level PMMCTL0_L = PMMCOREV0 * level; //Set SVM, SVS low side to new level SVSMLCTL = SVMLE | (SVSMLRRL0 * level) | SVSLE | (SVSLRVL0 * level); //Wait until SVM, SVS low side is settled while((PMMIFG & SVSMLDLYIFG) == 0) { ; } //Clear flag PMMIFG &= ~SVSMLDLYIFG; //SVS, SVM core and high side are now set to protect for the new core level //Restore Low side settings //Clear all other bits _except_ level settings SVSMLCTL &= (SVSLRVL0 + SVSLRVL1 + SVSMLRRL0 + SVSMLRRL1 + SVSMLRRL2 ); //Clear level settings in the backup register,keep all other bits SVSMLCTL_backup &= ~(SVSLRVL0 + SVSLRVL1 + SVSMLRRL0 + SVSMLRRL1 + SVSMLRRL2); //Restore low-side SVS monitor settings SVSMLCTL |= SVSMLCTL_backup; //Restore High side settings //Clear all other bits except level settings SVSMHCTL &= (SVSHRVL0 + SVSHRVL1 + SVSMHRRL0 + SVSMHRRL1 + SVSMHRRL2 ); //Clear level settings in the backup register,keep all other bits SVSMHCTL_backup &= ~(SVSHRVL0 + SVSHRVL1 + SVSMHRRL0 + SVSMHRRL1 + SVSMHRRL2); //Restore backup SVSMHCTL |= SVSMHCTL_backup; //Wait until high side, low side settled while(((PMMIFG & SVSMLDLYIFG) == 0) && ((PMMIFG & SVSMHDLYIFG) == 0)) { ; } //Clear all Flags PMMIFG &= ~(SVMHVLRIFG | SVMHIFG | SVSMHDLYIFG | SVMLVLRIFG | SVMLIFG | SVSMLDLYIFG ); //Restore PMM interrupt enable register PMMRIE = PMMRIE_backup; //Lock PMM registers for write access PMMCTL0_H = 0x00; return true; } bool increaseVCoreToLevel2() { uint8_t level = 2; uint8_t actlevel; bool status = true; //Set Mask for Max. level level &= PMMCOREV_3; //Get actual VCore actlevel = PMMCTL0 & PMMCOREV_3; //step by step increase or decrease while((level != actlevel) && (status == true)) { if(level > actlevel) { status = setVCoreUp(++actlevel); } } return (status); } void initGPIO() { //LEDs P1OUT = 0x00; // P1 setup for LED & reset output P1DIR |= BIT0; P4DIR |= BIT7; P4OUT &= ~(BIT7); //I2C Pins P3SEL |= BIT0 + BIT1; // P3.0,1 option select } void initI2C() { UCB0CTL1 |= UCSWRST; // Enable SW reset UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode UCB0CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset UCB0BR0 = 192; // fSCL = SMCLK/12 = ~100kHz UCB0BR1 = 0; UCB0I2CSA = 0x48; // Slave Address is 048h UCB0CTL1 &= ~UCSWRST; // Clear SW reset, resume operation UCB0IE |= UCNACKIE; } int main(void) { WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer increaseVCoreToLevel2(); initClockTo16MHz(); initGPIO(); initI2C(); I2C_Master_WriteReg(SLAVE_ADDR, CMD_TYPE_0_MASTER, MasterType0, TYPE_0_LENGTH); I2C_Master_WriteReg(SLAVE_ADDR, CMD_TYPE_1_MASTER, MasterType1, TYPE_1_LENGTH); I2C_Master_WriteReg(SLAVE_ADDR, CMD_TYPE_2_MASTER, MasterType2, TYPE_2_LENGTH); I2C_Master_ReadReg(SLAVE_ADDR, CMD_TYPE_0_SLAVE, TYPE_0_LENGTH); CopyArray(ReceiveBuffer, SlaveType0, TYPE_0_LENGTH); I2C_Master_ReadReg(SLAVE_ADDR, CMD_TYPE_1_SLAVE, TYPE_1_LENGTH); CopyArray(ReceiveBuffer, SlaveType1, TYPE_1_LENGTH); I2C_Master_ReadReg(SLAVE_ADDR, CMD_TYPE_2_SLAVE, TYPE_2_LENGTH); CopyArray(ReceiveBuffer, SlaveType2, TYPE_2_LENGTH); __bis_SR_register(LPM0_bits + GIE); return 0; } #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__) #pragma vector=USCI_B0_VECTOR __interrupt void USCI_B0_ISR(void) #elif defined(__GNUC__) void __attribute__ ((interrupt(USCI_B0_VECTOR))) USCI_B0_ISR (void) #else #error Compiler not supported! #endif { //Must read from UCB0RXBUF uint8_t rx_val = 0; switch(__even_in_range(UCB0IV,0xC)) { case USCI_NONE:break; // Vector 0 - no interrupt case USCI_I2C_UCALIFG:break; // Interrupt Vector: I2C Mode: UCALIFG case USCI_I2C_UCNACKIFG:break; // Interrupt Vector: I2C Mode: UCNACKIFG case USCI_I2C_UCSTTIFG:break; // Interrupt Vector: I2C Mode: UCSTTIFG case USCI_I2C_UCSTPIFG:break; // Interrupt Vector: I2C Mode: UCSTPIFG case USCI_I2C_UCRXIFG: rx_val = UCB0RXBUF; if (RXByteCtr) { ReceiveBuffer[ReceiveIndex++] = rx_val; RXByteCtr--; } if (RXByteCtr == 1) { UCB0CTL1 |= UCTXSTP; } else if (RXByteCtr == 0) { UCB0IE &= ~UCRXIE; MasterMode = IDLE_MODE; __bic_SR_register_on_exit(CPUOFF); // Exit LPM0 } break; // Interrupt Vector: I2C Mode: UCRXIFG case USCI_I2C_UCTXIFG: switch (MasterMode) { case TX_REG_ADDRESS_MODE: UCB0TXBUF = TransmitRegAddr; if (RXByteCtr) MasterMode = SWITCH_TO_RX_MODE; // Need to start receiving now else MasterMode = TX_DATA_MODE; // Continue to transmision with the data in Transmit Buffer break; case SWITCH_TO_RX_MODE: UCB0IE |= UCRXIE; // Enable RX interrupt UCB0IE &= ~UCTXIE; // Disable TX interrupt UCB0CTL1 &= ~UCTR; // Switch to receiver MasterMode = RX_DATA_MODE; // State state is to receive data UCB0CTL1 |= UCTXSTT; // Send repeated start if (RXByteCtr == 1) { //Must send stop since this is the N-1 byte while((UCB0CTL1 & UCTXSTT)); UCB0CTL1 |= UCTXSTP; // Send stop condition } break; case TX_DATA_MODE: if (TXByteCtr) { UCB0TXBUF = TransmitBuffer[TransmitIndex++]; TXByteCtr--; } else { //Done with transmission UCB0CTL1 |= UCTXSTP; // Send stop condition MasterMode = IDLE_MODE; UCB0IE &= ~UCTXIE; // disable TX interrupt //IFG2 &= ~(UCB0TXIFG); __bic_SR_register_on_exit(CPUOFF); // Exit LPM0 } break; default: __no_operation(); break; } break; // Interrupt Vector: I2C Mode: UCTXIFG default: break; } } I2C_Mode I2C_Master_ReadReg(uint8_t dev_addr, uint8_t reg_addr, uint8_t count) { /* Initialize state machine */ MasterMode = TX_REG_ADDRESS_MODE; TransmitRegAddr = reg_addr; RXByteCtr = count; TXByteCtr = 0; ReceiveIndex = 0; TransmitIndex = 0; /* Initialize slave address and interrupts */ UCB0I2CSA = dev_addr; UCB0IFG &= ~(UCTXIFG + UCRXIFG); // Clear any pending interrupts UCB0IE &= ~UCRXIE; // Disable RX interrupt UCB0IE |= UCTXIE; // Enable TX interrupt UCB0CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition __bis_SR_register(LPM0_bits + GIE); // Enter LPM0 w/ interrupts return MasterMode; } I2C_Mode I2C_Master_WriteReg(uint8_t dev_addr, uint8_t reg_addr, uint8_t *reg_data, uint8_t count) { /* Initialize state machine */ MasterMode = TX_REG_ADDRESS_MODE; TransmitRegAddr = reg_addr; //Copy register data to TransmitBuffer CopyArray(reg_data, TransmitBuffer, count); TXByteCtr = count; RXByteCtr = 0; ReceiveIndex = 0; TransmitIndex = 0; /* Initialize slave address and interrupts */ UCB0I2CSA = dev_addr; UCB0IFG &= ~(UCTXIFG + UCRXIFG); // Clear any pending interrupts UCB0IE &= ~UCRXIE; // Disable RX interrupt UCB0IE |= UCTXIE; // Enable TX interrupt UCB0CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition __bis_SR_register(LPM0_bits + GIE); // Enter LPM0 w/ interrupts return MasterMode; } void CopyArray(uint8_t *source, uint8_t *dest, uint8_t count) { uint8_t copyIndex = 0; for (copyIndex = 0; copyIndex < count; copyIndex++) { dest[copyIndex] = source[copyIndex]; } }
#include <msp430.h> #include <stdint.h> #define SLAVE_ADDR 0x48 #define CMD_TYPE_0_SLAVE 0 #define CMD_TYPE_1_SLAVE 1 #define CMD_TYPE_2_SLAVE 2 #define CMD_TYPE_0_MASTER 3 #define CMD_TYPE_1_MASTER 4 #define CMD_TYPE_2_MASTER 5 #define TYPE_0_LENGTH 1 #define TYPE_1_LENGTH 2 #define TYPE_2_LENGTH 6 #define MAX_BUFFER_SIZE 20 typedef enum I2C_ModeEnum{ IDLE_MODE, NACK_MODE, TX_REG_ADDRESS_MODE, RX_REG_ADDRESS_MODE, TX_DATA_MODE, RX_DATA_MODE, SWITCH_TO_RX_MODE, SWITHC_TO_TX_MODE, TIMEOUT_MODE } I2C_Mode; uint8_t MasterType2 [TYPE_2_LENGTH] = {0}; uint8_t MasterType1 [TYPE_1_LENGTH] = { 0, 0}; uint8_t MasterType0 [TYPE_0_LENGTH] = { 0}; uint8_t SlaveType2 [TYPE_2_LENGTH] = {'A', 'B', 'C', 'D', '1', '2'}; uint8_t SlaveType1 [TYPE_1_LENGTH] = {15, 16}; uint8_t SlaveType0 [TYPE_0_LENGTH] = {12}; I2C_Mode SlaveMode = RX_REG_ADDRESS_MODE; uint8_t ReceiveRegAddr = 0; uint8_t ReceiveBuffer[MAX_BUFFER_SIZE] = {0}; uint8_t RXByteCtr = 0; uint8_t ReceiveIndex = 0; uint8_t TransmitBuffer[MAX_BUFFER_SIZE] = {0}; uint8_t TXByteCtr = 0; uint8_t TransmitIndex = 0; void initClockTo16MHz() { if (CALBC1_16MHZ==0xFF) // If calibration constant erased { while(1); // do not load, trap CPU!! } DCOCTL = 0; // Select lowest DCOx and MODx settings BCSCTL1 = CALBC1_16MHZ; // Set DCO DCOCTL = CALDCO_16MHZ; } void initGPIO() { P1SEL |= BIT6 + BIT7; // Assign I2C pins to USCI_B0 P1SEL2|= BIT6 + BIT7; // Assign I2C pins to USCI_B0 } void initI2C() { UCB0CTL1 |= UCSWRST; // Enable SW reset UCB0CTL0 = UCMODE_3 + UCSYNC; // I2C Slave, synchronous mode UCB0I2COA = 0x48; // Own Address is 048h UCB0CTL1 &= ~UCSWRST; // Clear SW reset, resume operation UCB0I2CIE |= UCSTPIE + UCSTTIE; // Enable STT and STP interrupt IE2 |= UCB0RXIE; // Enable RX interrupt } inline void I2C_Slave_ProcessCMD(uint8_t cmd); inline void I2C_Slave_TransactionDone(uint8_t cmd); inline void CopyArray(uint8_t *source, uint8_t *dest, uint8_t count); int main(void) { WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer initClockTo16MHz(); initGPIO(); initI2C(); __bis_SR_register(LPM0_bits + GIE); return 0; } //------------------------------------------------------------------------------ // The USCI_B0 data ISR is used to move data from MSP430 memory to the // I2C master. PTxData points to the next byte to be transmitted, and TXByteCtr // keeps track of the number of bytes transmitted. //------------------------------------------------------------------------------ #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 Data Interrupt { //Must read from UCB0RXBUF uint8_t rx_val = UCB0RXBUF; switch (SlaveMode) { case (RX_REG_ADDRESS_MODE): ReceiveRegAddr = rx_val; I2C_Slave_ProcessCMD(ReceiveRegAddr); break; case (RX_DATA_MODE): ReceiveBuffer[ReceiveIndex++] = rx_val; RXByteCtr--; if (RXByteCtr == 0) { //Done Receiving MSG SlaveMode = RX_REG_ADDRESS_MODE; IE2 &= ~(UCB0TXIE); IE2 |= UCB0RXIE; // Enable RX interrupt I2C_Slave_TransactionDone(ReceiveRegAddr); } break; default: _no_operation(); break; } } else if (IFG2 & UCB0TXIFG) // Transmit Data Interrupt { //Must write to UCB0TXBUF switch (SlaveMode) { case (TX_DATA_MODE): UCB0TXBUF = TransmitBuffer[TransmitIndex++]; TXByteCtr--; if (TXByteCtr == 0) { //Done Transmitting MSG SlaveMode = RX_REG_ADDRESS_MODE; IE2 &= ~(UCB0TXIE); IE2 |= UCB0RXIE; // Enable RX interrupt I2C_Slave_TransactionDone(ReceiveRegAddr); } break; default: _no_operation(); break; } } } //------------------------------------------------------------------------------ // The USCI_B0 state ISR is used to wake up the CPU from LPM0 in order to do // processing in the main program after data has been transmitted. LPM0 is // only exit in case of a (re-)start or stop condition when actual data // was transmitted. //------------------------------------------------------------------------------ #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__) #pragma vector = USCIAB0RX_VECTOR __interrupt void USCIAB0RX_ISR(void) #elif defined(__GNUC__) void __attribute__ ((interrupt(USCIAB0RX_VECTOR))) USCIAB0RX_ISR (void) #else #error Compiler not supported! #endif { if (UCB0STAT & UCSTPIFG) //Stop or NACK Interrupt { UCB0STAT &= ~(UCSTTIFG + UCSTPIFG + UCNACKIFG); //Clear START/STOP/NACK Flags } if (UCB0STAT & UCSTTIFG) { UCB0STAT &= ~(UCSTTIFG); //Clear START Flags } } inline void I2C_Slave_ProcessCMD(uint8_t cmd) { ReceiveIndex = 0; TransmitIndex = 0; RXByteCtr = 0; TXByteCtr = 0; switch (cmd) { case (CMD_TYPE_0_SLAVE): //Send slave device id (This device's id) SlaveMode = TX_DATA_MODE; TXByteCtr = TYPE_0_LENGTH; //Fill out the TransmitBuffer CopyArray(SlaveType0, TransmitBuffer, TYPE_0_LENGTH); IE2 &= ~UCB0RXIE; // Disable RX interrupt IE2 |= UCB0TXIE; // Enable TX interrupt break; case (CMD_TYPE_1_SLAVE): //Send slave device time (This device's time) SlaveMode = TX_DATA_MODE; TXByteCtr = TYPE_1_LENGTH; //Fill out the TransmitBuffer CopyArray(SlaveType1, TransmitBuffer, TYPE_1_LENGTH); IE2 &= ~UCB0RXIE; // Disable RX interrupt IE2 |= UCB0TXIE; // Enable TX interrupt break; case (CMD_TYPE_2_SLAVE): //Send slave device location (This device's location) SlaveMode = TX_DATA_MODE; TXByteCtr = TYPE_2_LENGTH; //Fill out the TransmitBuffer CopyArray(SlaveType2, TransmitBuffer, TYPE_2_LENGTH); IE2 &= ~UCB0RXIE; // Disable RX interrupt IE2 |= UCB0TXIE; // Enable TX interrupt break; case (CMD_TYPE_0_MASTER): SlaveMode = RX_DATA_MODE; RXByteCtr = TYPE_0_LENGTH; IE2 &= ~UCB0TXIE; // Disable RX interrupt IE2 |= UCB0RXIE; // Enable TX interrupt break; case (CMD_TYPE_1_MASTER): SlaveMode = RX_DATA_MODE; RXByteCtr = TYPE_1_LENGTH; IE2 &= ~UCB0TXIE; // Disable RX interrupt IE2 |= UCB0RXIE; // Enable TX interrupt break; case (CMD_TYPE_2_MASTER): SlaveMode = RX_DATA_MODE; RXByteCtr = TYPE_2_LENGTH; IE2 &= ~UCB0TXIE; // Disable RX interrupt IE2 |= UCB0RXIE; // Enable TX interrupt break; default: _no_operation(); break; } } inline void I2C_Slave_TransactionDone(uint8_t cmd) { switch (cmd) { case (CMD_TYPE_0_SLAVE): //Slave device id was sent(This device's id) break; case (CMD_TYPE_1_SLAVE): //Slave device time was sent(This device's time) break; case (CMD_TYPE_2_SLAVE): //Send slave device location (This device's location) break; case (CMD_TYPE_0_MASTER): CopyArray(ReceiveBuffer, MasterType0, TYPE_0_LENGTH); break; case (CMD_TYPE_1_MASTER): CopyArray(ReceiveBuffer, MasterType1, TYPE_1_LENGTH); break; case (CMD_TYPE_2_MASTER): CopyArray(ReceiveBuffer, MasterType2, TYPE_2_LENGTH); break; default: _no_operation(); break; } } inline void CopyArray(uint8_t *source, uint8_t *dest, uint8_t count) { uint8_t copyIndex = 0; for (copyIndex = 0; copyIndex < count; copyIndex++) { dest[copyIndex] = source[copyIndex]; } }