Hi,
I'm using MSP430FR5729 controller in CCS6.1.0 version.
In below code i'll send one cmd from master and enabling Receiver interrupt.
At slave side first rx interrupt is enabled and after receiving one byte i'm enabling the Tx from slave.
when i execute this code is working fine and result i get is as expected.
This will fail if master sends WRITE cmd.
my doubt is how to send r/w bit from master and how to recognize command received is read or write.
Please suggest me the corrections to be made in my code so that the slave can respond to read / write command respectively.
Master Code: #include <msp430fr5729.h> //#define I2C_Master_Tx_Mode 1 #define I2C_Master_Rx_Mode 1 #define I2C_Flag_PEC (1<<0) #define Max_data_count 4 void CRC8_add(unsigned char* crc, unsigned char data); void I2C_Receive_data(unsigned char rx,unsigned char count); void I2C_Master_Tx_mode(void); void I2C_Master_Rx_mode(void); static const unsigned char _CRC8_table[256] = { 0x00, 0x07, 0x0e, 0x09, 0x1c, 0x1b, 0x12, 0x15, 0x38, 0x3f, 0x36, 0x31, 0x24, 0x23, 0x2a, 0x2d, 0x70, 0x77, 0x7e, 0x79, 0x6c, 0x6b, 0x62, 0x65, 0x48, 0x4f, 0x46, 0x41, 0x54, 0x53, 0x5a, 0x5d, 0xe0, 0xe7, 0xee, 0xe9, 0xfc, 0xfb, 0xf2, 0xf5, 0xd8, 0xdf, 0xd6, 0xd1, 0xc4, 0xc3, 0xca, 0xcd, 0x90, 0x97, 0x9e, 0x99, 0x8c, 0x8b, 0x82, 0x85, 0xa8, 0xaf, 0xa6, 0xa1, 0xb4, 0xb3, 0xba, 0xbd, 0xc7, 0xc0, 0xc9, 0xce, 0xdb, 0xdc, 0xd5, 0xd2, 0xff, 0xf8, 0xf1, 0xf6, 0xe3, 0xe4, 0xed, 0xea, 0xb7, 0xb0, 0xb9, 0xbe, 0xab, 0xac, 0xa5, 0xa2, 0x8f, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9d, 0x9a, 0x27, 0x20, 0x29, 0x2e, 0x3b, 0x3c, 0x35, 0x32, 0x1f, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0d, 0x0a, 0x57, 0x50, 0x59, 0x5e, 0x4b, 0x4c, 0x45, 0x42, 0x6f, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7d, 0x7a, 0x89, 0x8e, 0x87, 0x80, 0x95, 0x92, 0x9b, 0x9c, 0xb1, 0xb6, 0xbf, 0xb8, 0xad, 0xaa, 0xa3, 0xa4, 0xf9, 0xfe, 0xf7, 0xf0, 0xe5, 0xe2, 0xeb, 0xec, 0xc1, 0xc6, 0xcf, 0xc8, 0xdd, 0xda, 0xd3, 0xd4, 0x69, 0x6e, 0x67, 0x60, 0x75, 0x72, 0x7b, 0x7c, 0x51, 0x56, 0x5f, 0x58, 0x4d, 0x4a, 0x43, 0x44, 0x19, 0x1e, 0x17, 0x10, 0x05, 0x02, 0x0b, 0x0c, 0x21, 0x26, 0x2f, 0x28, 0x3d, 0x3a, 0x33, 0x34, 0x4e, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5c, 0x5b, 0x76, 0x71, 0x78, 0x7f, 0x6a, 0x6d, 0x64, 0x63, 0x3e, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2c, 0x2b, 0x06, 0x01, 0x08, 0x0f, 0x1a, 0x1d, 0x14, 0x13, 0xae, 0xa9, 0xa0, 0xa7, 0xb2, 0xb5, 0xbc, 0xbb, 0x96, 0x91, 0x98, 0x9f, 0x8a, 0x8d, 0x84, 0x83, 0xde, 0xd9, 0xd0, 0xd7, 0xc2, 0xc5, 0xcc, 0xcb, 0xe6, 0xe1, 0xe8, 0xef, 0xfa, 0xfd, 0xf4, 0xf3 }; //***************************************************************************** // Add the next value to the CRC. The calculations are pre-done and stored in // the above lookup table, this makes this a very fast operation at the expense // of 256 bytes of code space. //***************************************************************************** void CRC8_add(unsigned char* crc, unsigned char data) { *crc = _CRC8_table[*crc ^ data]; } // CRC8_add enum { ER_OK = 0, ER_CRC, }; enum { I2C_CMD = 0x00, I2C_Data_LSB, I2C_Data_MSB, I2C_Read_last, I2C_IDLE, I2C_Done, }; struct I2Cstate { unsigned char state; unsigned char addr; unsigned char cmd; unsigned char data[Max_data_count]; unsigned char count; unsigned char PecCalculated; unsigned char PecReceived; unsigned char flags; }; static volatile struct I2Cstate I2C; #ifdef I2C_Master_Tx_Mode //unsigned long TXData[8][2] ={{0x10,0x20},{0x11,0x5F},{0x12,0x36},{0x14,0x7B},{0x10,0x35},{0x11,0x54},{0x12,0x10},{0x14,0xE0}}; // TX data Variable //unsigned long TXData[4][2] ={{0x10,0x20},{0x11,0x5F},{0x12,0x36},{0x14,0x7B}}; unsigned long TXData[6][3] ={{0x10,0x20,0x00},{0x12,0x30,0x00},{0x15,0x02,0x01},{0x15,0xF4,0x01},{0x15,0x7B,0x00},{0x15,0x24,0x00}}; #endif #ifdef I2C_Master_Rx_Mode unsigned long TXData[6][3] = {{0x10,0x00,0x00},{0x10,0x00,0x00},{0x12,0x00,0x00},{0x13,0x00,0x00},{0x14,0x00,0x00},{0x15,0x00,0x00}}; #endif unsigned char RXData[3]; unsigned char TXByteCtr; unsigned char RXByteCtr; unsigned char i=0,j=0; unsigned char err; void I2C_init(void) { I2C.count = 4; // Inital count value I2C.flags = 1; // PEC Enabled I2C.state = I2C_IDLE; } void I2C_Master_Tx_mode(void) { I2C.count = 4; // Inital count value I2C.flags = 1; // PEC Enabled I2C.state = I2C_IDLE; } void I2C_Master_Rx_mode(void) { TXByteCtr = 1; I2C.flags = 1; // PEC Enabled I2C.state = I2C_IDLE; I2C.count = 0; } void run_I2C(void) { if(I2C.state == I2C_Done) { if((I2C.flags == I2C_Flag_PEC) && (I2C.PecCalculated!= I2C.PecReceived)) { err = ER_CRC; // CRC Error } else { err = ER_OK; // Transcation is ok } } } void I2C_Receive_data(unsigned char rx,unsigned char count) { if(count == 0) { I2C.data[0] = rx; if(I2C.flags & I2C_Flag_PEC) { CRC8_add((unsigned char *) &I2C.PecCalculated, rx); } } else if(count == 1) { if(TXData[j][0] == 0x15) { I2C.data[1] = rx; if(I2C.flags & I2C_Flag_PEC) { CRC8_add((unsigned char *) &I2C.PecCalculated, rx); } } else { I2C.PecReceived = rx; I2C.state = I2C_Done; I2C.count = 0; } } else if (count == 2) { I2C.PecReceived = rx; I2C.state = I2C_Done; I2C.count = 0; } } int main(void) { WDTCTL = WDTPW + WDTHOLD; // Init SMCLK = MCLk = ACLK = 1MHz CSCTL0_H = 0xA5; CSCTL1 |= DCOFSEL0 + DCOFSEL1; // Set max. DCO setting = 8MHz CSCTL2 = SELA_3 + SELS_3 + SELM_3; // set ACLK = MCLK = DCO CSCTL3 = DIVA_0 + DIVS_0 + DIVM_0; // set all dividers to 1MHz // Configure Pins for I2C P1SEL1 |= BIT6 + BIT7; // Pin init UCB0CTLW0 |= UCSWRST; // put eUSCI_B in reset state UCB0CTLW0 |= UCMODE_3 + UCMST + UCSSEL_2;// I2C master mode, SMCLk // UCB0BRW = 0x8; // baudrate = SMCLK / 8 UCB0I2CSA = 0x33; // address slave is 48hex UCB0CTLW0 &=~ UCSWRST; //clear reset register UCB0IE |= UCTXIE0 | UCRXIE0 | UCNACKIE; //transmit, Receive and NACK interrupt enable __bis_SR_register(GIE); // Enter LPM0 w/ interrupts // Remain in LPM0 until all data // is TX'd // UCB0CTLW0 |= UCTR + UCTXSTT; // I2C TX, start condition #ifdef I2C_Master_Tx_Mode I2C_Master_Tx_mode(); #endif #ifdef I2C_Master_Rx_Mode I2C_Master_Rx_mode(); #endif while(1) { __delay_cycles(1000); // Delay between transmissions #ifdef I2C_Master_Tx_Mode { if(TXData[j][0] == 0x15) { TXByteCtr = 4; } else { TXByteCtr = 3; } while (UCB0CTLW0 & UCTXSTP); // Ensure stop condition got sent run_I2C(); UCB0CTLW0 |= UCTR + UCTXSTT; // I2C TX, start condition } #endif #ifdef I2C_Master_Rx_Mode { while (UCB0CTLW0 & UCTXSTP); // Ensure stop condition got sent run_I2C(); UCB0CTLW0 |= UCTR + UCTXSTT; // I2C TX, start condition } #endif __delay_cycles(10000000); __delay_cycles(10000000); __delay_cycles(10000000); __delay_cycles(10000000); // TXData=0x10; // TXData++; // Increment data byte } } #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__) #pragma vector = USCI_B0_VECTOR __interrupt void USCIB0_ISR(void) #elif defined(__GNUC__) void __attribute__ ((interrupt(USCI_B0_VECTOR))) USCIB0_ISR (void) #else #error Compiler not supported! #endif { switch(__even_in_range(UCB0IV,0x1E)) { case 0x00: break; // Vector 0: No interrupts break; case 0x02: break; case 0x04: UCB0CTLW0 |= UCTXSTT; //resend start if NACK break; // Vector 4: NACKIFG break; case 0x16: #ifdef I2C_Master_Rx_Mode if(RXByteCtr) { if(RXByteCtr == 1) { UCB0CTLW0 |= UCTXSTP; // I2C stop condition } RXData[I2C.count] = UCB0RXBUF; I2C_Receive_data(RXData[I2C.count],I2C.count); I2C.count++; RXByteCtr--; } else { UCB0IFG &= ~UCRXIFG; // Clear USCI_B0 RX int flag // UCB0CTLW0 |= UCTXSTP; // I2C stop condition // UCB0CTLW0 |= UCTR + UCTXSTT; // I2C TX, start condition i = 0; if(j==5) { j = 0; } else { j++; } } #endif break; case 0x18: #ifdef I2C_Master_Tx_Mode { if(TXByteCtr) // Check TX byte counter { if(TXByteCtr == 1) { // UCB0TXBUF = _CRC8_table[I2C.PecCalculated ^ TXData[j][i]]; // Load TX buffer UCB0TXBUF = I2C.PecCalculated; // Load TX buffer TXByteCtr--; // Decrement TX byte counter i = 0; } else { UCB0TXBUF = TXData[j][i]; // Load TX buffer if(I2C.flags & I2C_Flag_PEC) { CRC8_add((unsigned char *) &I2C.PecCalculated,TXData[j][i]); } TXByteCtr--; // Decrement TX byte counter i++; } } else { UCB0CTLW0 |= UCTXSTP; // I2C stop condition UCB0IFG &= ~UCTXIFG; // Clear USCI_B0 TX int flag i=0; if(j==5) { j = 0; } else { j++; } // __bic_SR_register_on_exit(CPUOFF);// Exit LPM0 } } #endif #ifdef I2C_Master_Rx_Mode { if(TXByteCtr) // Check TX byte counter { UCB0TXBUF = TXData[j][i]; if(TXData[j][0] == 0x15) { RXByteCtr = 3; } else { RXByteCtr = 2; } TXByteCtr--; } else { UCB0IFG &= ~UCTXIFG; // Clear USCI_B0 TX int flag UCB0CTLW0 &= ~UCTR; // Clear I2C TX UCB0CTLW0 |= UCTXSTT; // I2C RX, start condition } } #endif break; // Vector 26: TXIFG0 break; default: break; } } Slave Code: #include <msp430fr5729.h> #define SLAVEADD 0x33 //#define I2C_Slave_Rx_mode 1 #define I2C_Slave_Tx_mode 1 unsigned char TXData; unsigned int TXByteCtr; extern unsigned long RXData; #define Max_data_count 4 // 1st byte cmd 2nd & 3rd byte data and 4th PEC #define I2C_Flag_PEC (1<<0) //unsigned char Batt1SOC_data, Batt2SOC_data, SystemStatus_data, PowerStatus_data, ErrorValue_data; //unsigned int RemainingTime_data; unsigned char Rxdata[3],Txdata[3],err; extern unsigned int ui_batt1_soc,ui_batt2_soc,ui_sys_status_data,ui_pow_status,ui_err,ui_time_remain; extern uchar write_cmd_recd; void I2C_Receive_data(unsigned char Rx,unsigned char i); void I2C_Transmit_data(void); void I2C_display_cmd_data(unsigned char cmd, unsigned char *data); unsigned char run_I2C(void); void I2C_init(void); enum { IDLE = 0x00, //No Interrupt ARBITRATION_LOST = 0X02, //ALIFG NO_ACK = 0X04, //NACKIFG START_RECD = 0x06, //STTIFG STOP_RECD = 0X08, //STPIFG SLAVE3_DATA_RECD = 0X0A, //RXIFG3 SLAVE3_TX_BUFF_EMP = 0x0C, //TXIFG3 SLAVE2_DATA_RECD = 0X0E, //RXIFG2 SLAVE2_TX_BUFF_EMP = 0x10, //TXIFG2 SLAVE1_DATA_RECD = 0X12, //RXIFG1 SLAVE1_TX_BUFF_EMP = 0X14, //TXIFG1 DATA_RECD = 0x16, //RXIFG0 TX_BUFF_EMP = 0X18, //TXIFG0 BYTE_CNT_ZERO = 0X1A, //BCNTIFG CLK_LOW_TIMEOUT = 0x1C, //CLOCK LOW TIMEOUT NINTH_BIT_POSITION = 0X1E //9TH BIT }; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// enum { ER_OK = 0, ER_CRC }; enum { I2C_CMD = 0x00, I2C_Data_LSB, I2C_Data_MSB, I2C_Read_last, I2C_IDLE, I2C_Done }; struct I2Cstate { unsigned char state; unsigned char cmd; unsigned char data[Max_data_count]; unsigned char count; unsigned char PecCalculated; unsigned char PecReceived; unsigned char flags; }; static volatile struct I2Cstate I2C; void I2C_init(void) { I2C.count = 0; // Inital count value I2C.flags = 1; // PEC Enabled I2C.state = I2C_IDLE; } unsigned char run_I2C(void) { if(I2C.state == I2C_Done) { if((I2C.flags == I2C_Flag_PEC) && (I2C.PecCalculated!= I2C.PecReceived)) { return ER_CRC; // CRC Error } else { return ER_OK; // Transcation is ok } } } /**************************************************************************************************************************************************** * Function Name : I2C_slaveinit * Purpose : This function initialise the device as a I2C slave * Input : Slave Address * Return : None *****************************************************************************************************************************************************/ void I2C_slaveinit(unsigned char slave_address) { P1SEL1 |= I2C_SDA + I2C_SCL; // Slave Config UCB0CTL1 |= UCSWRST; // Enable SW reset UCB0CTLW0 = UCMODE_3 + UCSYNC; // I2C Slave, synchronous mode UCB0I2COA0 = slave_address+UCOAEN; // set own (slave) address UCB0CTL1 &= ~UCSWRST; // Clear SW reset, resume operation UCB0IE |= UCRXIE0; // Enable Rx interrupt Enable ui_batt1_soc=50; ui_batt2_soc=80; ui_sys_status_data=0x35; ui_pow_status=0x00; ui_err=989; ui_time_remain=314; } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #pragma vector = USCI_B0_VECTOR __interrupt void USCIB0_ISR(void) { switch(__even_in_range(UCB0IV,0x1E)) { case IDLE: break; // Vector 0: No interrupts break; case ARBITRATION_LOST: break; // Vector 2: ALIFG break; case NO_ACK: break; // Vector 4: NACKIFG break; case START_RECD: break; // Vector 6: STTIFG break; case STOP_RECD: UCB0IFG &= ~UCSTPIFG; // Clear stop condition int flag UCB0IE &= ~UCTXIE0; //------R break; // Vector 8: STPIFG break; case SLAVE3_DATA_RECD: break; // Vector 10: RXIFG3 break; case SLAVE3_TX_BUFF_EMP: break; // Vector 14: TXIFG3 break; case SLAVE2_DATA_RECD: break; // Vector 16: RXIFG2 break; case SLAVE2_TX_BUFF_EMP: break; // Vector 18: TXIFG2 break; case SLAVE1_DATA_RECD: break; // Vector 20: RXIFG1 break; case SLAVE1_TX_BUFF_EMP: break; // Vector 22: TXIFG1 break; case DATA_RECD: #ifdef I2C_Slave_Rx_mode { Rxdata[I2C.count] = UCB0RXBUF; // Get RX data I2C_Receive_data(Rxdata[I2C.count],I2C.count); I2C.count++; if(Rxdata[0] == 0x15) { if(I2C.count == 4) { I2C.count = 0; I2C_display_cmd_data(I2C.cmd, &I2C.data); } } else { if(I2C.count == 3) { I2C.count = 0; I2C_display_cmd_data(I2C.cmd, &I2C.data); } } break; // Vector 24: RXIFG0 break; } #endif #ifdef I2C_Slave_Tx_mode { Rxdata[0] = UCB0RXBUF; // Get RX data if(Rxdata[0] == 0x15) { TXByteCtr = 3; } else { TXByteCtr = 2; } UCB0IE |= UCTXIE0; UCB0IFG &= ~UCTXIFG; break; // Vector 24: RXIFG0 break; } #endif case TX_BUFF_EMP: #ifdef I2C_Slave_Tx_mode { I2C_Transmit_data(); } #endif break; // Vector 26: TXIFG0 break; case BYTE_CNT_ZERO: break; // Vector 28: BCNTIFG break; case CLK_LOW_TIMEOUT: break; // Vector 30: clock low timeout break; case NINTH_BIT_POSITION: break; // Vector 32: 9th bit break; default: break; } } void I2C_Transmit_data(void) { if(Rxdata[0] == 0x10) { if(TXByteCtr == 1) { UCB0TXBUF = I2C.PecCalculated; TXByteCtr--; } else { UCB0TXBUF = ui_batt1_soc; if(I2C.flags & I2C_Flag_PEC) { CRC8_add((unsigned char *) &I2C.PecCalculated, ui_batt1_soc); } TXByteCtr--; } } else if(Rxdata[0] == 0x11) { if(TXByteCtr == 1) { UCB0TXBUF = I2C.PecCalculated; TXByteCtr--; } else if(TXByteCtr == 2) { UCB0TXBUF = ui_batt2_soc; if(I2C.flags & I2C_Flag_PEC) { CRC8_add((unsigned char *) &I2C.PecCalculated, ui_batt2_soc); } TXByteCtr--; } } else if(Rxdata[0] == 0x12) { if(TXByteCtr == 1) { UCB0TXBUF = I2C.PecCalculated; TXByteCtr--; } else { UCB0TXBUF = ui_sys_status_data; if(I2C.flags & I2C_Flag_PEC) { CRC8_add((unsigned char *) &I2C.PecCalculated, ui_sys_status_data); } TXByteCtr--; } } else if(Rxdata[0] == 0x13) { if(TXByteCtr == 1) { UCB0TXBUF = I2C.PecCalculated; TXByteCtr--; } else { UCB0TXBUF = ui_pow_status; if(I2C.flags & I2C_Flag_PEC) { CRC8_add((unsigned char *) &I2C.PecCalculated, ui_pow_status); } TXByteCtr--; } } else if(Rxdata[0] == 0x14) { if(TXByteCtr == 1) { UCB0TXBUF = I2C.PecCalculated; TXByteCtr--; } else { UCB0TXBUF = ui_err; if(I2C.flags & I2C_Flag_PEC) { CRC8_add((unsigned char *) &I2C.PecCalculated, ui_err); } TXByteCtr--; } } else if(Rxdata[0] == 0x15) { if(TXByteCtr == 1) { UCB0TXBUF = I2C.PecCalculated; TXByteCtr--; } else if (TXByteCtr == 2) { UCB0TXBUF = ((ui_time_remain & 0xFF00)>>8); if(I2C.flags & I2C_Flag_PEC) { CRC8_add((unsigned char *) &I2C.PecCalculated, ((ui_time_remain & 0xFF00)>>8)); } TXByteCtr--; } else if (TXByteCtr == 3) { UCB0TXBUF = (ui_time_remain & 0x00FF); if(I2C.flags & I2C_Flag_PEC) { CRC8_add((unsigned char *) &I2C.PecCalculated, (ui_time_remain & 0x00FF)); } TXByteCtr--; } } } void I2C_Receive_data(unsigned char rx,unsigned char count) { if(count == I2C_CMD) { // if(I2C.state == I2C_IDLE) { I2C.cmd = rx; if(I2C.flags & I2C_Flag_PEC) { CRC8_add((unsigned char *) &I2C.PecCalculated, I2C.cmd); } } } else if(count == I2C_Data_LSB) { I2C.data[0] = rx; if(I2C.flags & I2C_Flag_PEC) { CRC8_add((unsigned char *) &I2C.PecCalculated, rx); } } else if(count == I2C_Data_MSB) { if(I2C.cmd == 0x15) { I2C.data[1] = rx; if(I2C.flags & I2C_Flag_PEC) { CRC8_add((unsigned char *) &I2C.PecCalculated, rx); } } else { I2C.PecReceived = rx; I2C.state = I2C_Done; } } else if (count == I2C_Read_last) { I2C.PecReceived = rx; I2C.state = I2C_Done; } } void I2C_display_cmd_data(unsigned char cmd, unsigned char *data) { if(cmd == BAT1_SOC) { ui_batt1_soc = data[0]; write_cmd_recd = 1; } else if(cmd == BAT2_SOC) { ui_batt2_soc = data[0]; write_cmd_recd = 1; } else if(cmd == SYS_STATUS) { ui_sys_status_data = data[0]; write_cmd_recd = 1; } else if(cmd == POW_STATUS) { ui_pow_status = data[0]; write_cmd_recd = 1; } else if(cmd == ERROR_VAL) { ui_err = data[0]; write_cmd_recd = 1; } else if(cmd == REM_TIME) { ui_time_remain = ((data[1]<<8)+data[0]); write_cmd_recd = 1; } }