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.

BQ78350-R1: Complete Solution - AFE + Gas Gauge + MCU

Part Number: BQ78350-R1
Other Parts Discussed in Thread: BQ76940, BQ78350, EV2400, , BQ76940EVM, BQ76200

Hello,

We are planning to use BQ76940 + BQ78350 + MSP430 in LiFePO4 battery energy storage system. The MSP430 will be use for communication with the external world via RS485 - Modbus RTU.

1) Is it possible to communicate the BQ78350 with MSP430 via its I2C port? Is there any example code or reference design? 

2) Which part number of MSP430 would you recommend for it?

3) Is it really necessary to use an MCU for this communication or there is another way?

Thank you,

    • Hi,
    • You can check the timing requirement in the datasheet of bq78350 and see if the iic port of msp430 can support this timing.
    • Another way is to use 2 GPIOs of msp430 to simulate the timing of smbus to communicate with gauge.
    • smbus is a digital communication port that we need to use a device that support digital communication to achieve this 

  • Hello, Terry. Thank you for your attention.or

    Is there any application note/sample code with informations and guidelines for applications where the bq78350 communicates with a MSP430?
  • Hi Mauro,

    Just a few clarifications:

    Mauro Basquera said:
    1) Is it possible to communicate the BQ78350 with MSP430 via its I2C port? Is there any example code or reference design? 

    I am not sure that I understand what you mean but here is how the BQ78350 + BQ76940 work together:

    The I2C port of the B78350 is used to communicate with the BQ76940. You would not be able to interface with your MSP430 through the I2C port. You must use the SMBus port of the BQ78350.

    Mauro Basquera said:
    3) Is it really necessary to use an MCU for this communication or there is another way?

    If you have a I2C to your computer (ex: I2C-USB such as the Aardvaark), you could communicate with a PC. You could also use the EV2300 or EV2400 but I don't know the computer interface.

    Otherwise, you should use a microcontroller to communicate with the BQ78350.

    Once it is configured, the BQ78350 can also be used as a stand-alone unit to protect the battey. You just wouldn't know the status of the device.

    Regards,

    Michel

  • Hello, Michel.

    Sorry if I was not clear.
    Thank you for your response.

    Is there any application note/sample code with informations and guidelines for applications where the bq78350 communicates with a MSP430 via SMBus?

    Best regards,
  • Hi Mauro,

    There is an application note on the TI BQ78350-R1 page. Look in the technical documents section.

    There is no sample code as I know, but I have attached the SMBus code that we have used. It has the configuration for a MSP4305338.

    /*
     * SMBus.c
     *
     *  Created on: Sep 4, 2014
     *      Author: msolecki
     *
     *      We use TA1 for timeout check for the SMBus
     */
    
    #include <msp430.h>
    #include "include/include.h"
    #include "include/SMBus.h"
    
    #define BQ78350_ADDR		(0x16>>1)
    #define MFR_BLK_ACCESS		0x44
    #define MAX_QUEUE			75
    #define MAX_RX_LEN			50
    #define MAX_TX_LEN			10
    #define CRC8_POLY			0x07
    #define CRC8_INIT_REM		0x00
    
    //SMBus maximum cumulative clock stretching from start to stop is 25ms.  Give a little slack to avoid useless errors.
    #define TIMERSMBUS_TIMEOUT	((TIMERSMB_CLK_FREQ / (TIMERSMB_PDIV * TIMERSMB_IDIV)) * 26/1000)
    
    #define TIMERSMBUS_2MS		(TIMERSMB_CLK_FREQ / (500 * TIMERSMB_PDIV * TIMERSMB_IDIV))
    
    typedef struct message_t {
    	unsigned char address;
    	read_write mess_dir;
    	unsigned char is_block;
    	unsigned char tx_data[MAX_TX_LEN];
    	unsigned int tx_cnt;
    	unsigned char *rx_data;
    	unsigned int rx_cnt;
    	unsigned char nack;
    	void (*rx_done_callback)(unsigned char);
    	unsigned char id;
    } message;
    
    typedef struct message_queue_t {
    	message mess_q[MAX_QUEUE];
    	unsigned int mess_q_cnt;
    	unsigned int mess_q_in;
    	unsigned int mess_q_out;
    } message_queue;
    
    static unsigned char crc8MakeBitwise(unsigned char CRC, unsigned char Poly,
    		unsigned char *Pmsg, unsigned int Msg_Size);
    
    smbus_state cur_state = smbus_idle;
    unsigned int error_flag;
    unsigned int tx_done_flag;
    unsigned int mess_done_flag;
    
    unsigned int timer_delay_over;
    
    unsigned long nack_cntr;
    
    volatile message *cur_mess;
    message_queue smbus_queue;
    
    volatile unsigned char *PTxData;
    volatile unsigned char *PRxData;
    volatile unsigned char TXByteCtr;
    volatile unsigned char RXByteCtr;
    
    void smbus_q_init(void) {
    	smbus_queue.mess_q_cnt = 0;
    	smbus_queue.mess_q_in = 0;
    	smbus_queue.mess_q_out = 0;
    }
    
    // This function assumes the SMBus module is already properly configured.
    void smbus_reset(void) {
    
    	UCB1CTL1 |= UCTXSTP;	//Force a stop right away
    	TA1CTL = MC__STOP;		//Stop the timeout counter
    	UCB1CTL1 |= UCSWRST;		//Reset SMBus module
    
    	cur_state = smbus_down;
    }
    
    void smbus_resume(void) {
    	UCB1CTL1 &= ~UCSWRST;	//Enable SMBus module
    }
    
    void smbus_init(void) {
    
    	UCB1CTL1 = UCSWRST;	//place UCB in reset state
    
    	cur_state = smbus_idle;
    	error_flag = 0;
    	timer_delay_over = 0;
    	tx_done_flag = 0;
    	mess_done_flag = 0;
    	nack_cntr = 0;
    	smbus_q_init();
    
    	PSEL_MODE_MODULE(P8SEL, BIT5 | BIT6);
    	//P8SEL |= BIT5 | BIT6;		//set IO for SMBus
    
    	// set UCB in I2C mode
    	// multiple masters | master | I2C mode | synchronous for I2C | Clk source: AUXILIARY CLK (ACLK)
    	UCB1CTL0 = UCMST | UCMODE_3 | UCSYNC; //UCMM |
    	UCB1CTL1 |= SMBUS_CLK_SRC;
    
    	UCB1I2COA = 0x08;	//set own address
    
    	//set frequency to 100kHz
    	UCB1BR0 = ((SMBUS_CLK_FREQ / SMBUS_FREQ) & 0xFF);
    	UCB1BR1 = (((SMBUS_CLK_FREQ / SMBUS_FREQ) >> 8) & 0xFF);
    
    	UCB1IFG &= 0xFF;	//Clear all flags
    
    	UCB1I2CSA = BQ78350_ADDR;			// Slave Address is 1st byte of PayLoad
    	UCB1CTL1 &= ~UCSWRST;					// Clear SW reset, resume operation
    	UCB1IE |= UCTXIE + UCRXIE + UCNACKIE;	// Enable TX, RX, NACK interrupt
    
    	TA1CCR0 = TIMERSMBUS_TIMEOUT;		// Set top value for CCR0
    	TA1CCR1 = TIMERSMBUS_2MS;// Set timeout value for CCR1 (only used to add delay between frames)
    }
    
    unsigned char smbus_is_queue_full(void) {
    
    	if(smbus_queue.mess_q_cnt == MAX_QUEUE)
    		return 1;
    
    	return 0;
    }
    
    smbus_state smbus_get_state(void) {
    	return cur_state;
    }
    
    void smbus_requestWord(unsigned char addr, unsigned char id, unsigned char *return_data, void (*rx_done_callback)(unsigned char)) {
    	message *new_mess;
    
    	if (smbus_queue.mess_q_cnt < MAX_QUEUE) {
    		new_mess = &smbus_queue.mess_q[smbus_queue.mess_q_in];
    
    		//add data to message queue
    		new_mess->address = BQ78350_ADDR;
    		new_mess->mess_dir = read_mess;
    		new_mess->is_block = 0;
    		new_mess->tx_data[0] = addr;
    		new_mess->tx_cnt = 1;
    		new_mess->rx_data = return_data;
    		new_mess->rx_cnt = 3;
    		new_mess->nack = 0;
    		new_mess->rx_done_callback = rx_done_callback;
    		new_mess->id = id;
    
    		//update queue pointers
    		smbus_queue.mess_q_in++;
    		if (smbus_queue.mess_q_in == MAX_QUEUE) smbus_queue.mess_q_in = 0;
    		smbus_queue.mess_q_cnt++;
    	}
    }
    
    void smbus_requestMfrAccessReg(unsigned int acc_addr, unsigned char id, unsigned char *return_data, void (*rx_done_callback)(unsigned char)) {
    	unsigned int i;
    	message *new_mess;
    	unsigned char stream[MAX_TX_LEN + 1];
    	if (smbus_queue.mess_q_cnt < MAX_QUEUE - 1) { //queue must have 2 spaces left to request
    		new_mess = &smbus_queue.mess_q[smbus_queue.mess_q_in];
    
    		// Add data request to queue (1st message)
    		new_mess->address = BQ78350_ADDR;
    		new_mess->mess_dir = write_mess;
    		new_mess->is_block = 0;
    		stream[0] = BQ78350_ADDR << 1;
    		stream[1] = MFR_BLK_ACCESS; // SBS command: 0x44 Manufacturer Block Access function
    		stream[2] = 2; 						// Tx block length : 2
    		stream[3] = (unsigned char) acc_addr & 0xFF;	//Mfr address LSB
    		stream[4] = (unsigned char) (acc_addr >> 8) & 0xFF;	//Mfr address MSB
    
    		for (i = 0; i < 4; i++) {
    			new_mess->tx_data[i] = stream[i + 1];
    		}
    
    		new_mess->tx_data[4] = crc8MakeBitwise(CRC8_INIT_REM, CRC8_POLY,
    				&stream[0], 5);
    		new_mess->tx_cnt = 5;
    		new_mess->rx_data = 0;
    		new_mess->rx_cnt = 0;
    		new_mess->nack = 0;
    
    		//update queue pointers
    		smbus_queue.mess_q_in++;
    		if (smbus_queue.mess_q_in == MAX_QUEUE) smbus_queue.mess_q_in = 0;
    		smbus_queue.mess_q_cnt++;
    
    		// Add message to fetch data (2nd message)
    		new_mess = &smbus_queue.mess_q[smbus_queue.mess_q_in];
    		new_mess->address = BQ78350_ADDR;
    		new_mess->mess_dir = read_mess;
    		new_mess->is_block = 1;
    		new_mess->tx_data[0] = MFR_BLK_ACCESS;// SBS command: 0x44 Manufacturer Block Access function
    		new_mess->tx_cnt = 1;
    		new_mess->rx_data = return_data;
    		new_mess->rx_cnt = 2;
    		new_mess->nack = 0;
    		new_mess->id = id;
    		new_mess->rx_done_callback = rx_done_callback;
    
    		//update queue pointers
    		smbus_queue.mess_q_in++;
    		if (smbus_queue.mess_q_in == MAX_QUEUE) smbus_queue.mess_q_in = 0;
    		smbus_queue.mess_q_cnt++;
    	}
    }
    
    void smbus_writeWord(unsigned char addr, unsigned char *data) {
    	message *new_mess;
    
    	if (smbus_queue.mess_q_cnt < MAX_QUEUE) {
    		new_mess = &smbus_queue.mess_q[smbus_queue.mess_q_in];
    
    		new_mess->address = BQ78350_ADDR;
    		new_mess->mess_dir = write_mess;
    		new_mess->is_block = 0;
    		new_mess->tx_data[0] = addr;
    		new_mess->tx_data[1] = *data;
    		new_mess->tx_data[2] = *(data + 1);
    
    		//update queue pointers
    		smbus_queue.mess_q_in++;
    		if (smbus_queue.mess_q_in == MAX_QUEUE) smbus_queue.mess_q_in = 0;
    		smbus_queue.mess_q_cnt++;
    	}
    }
    
    void smbus_writeBlock(unsigned char *data, unsigned int length) {
    	message *new_mess;
    	unsigned char stream[MAX_TX_LEN + 4];
    	unsigned int i;
    
    	if (smbus_queue.mess_q_cnt < MAX_QUEUE) {
    		new_mess = &smbus_queue.mess_q[smbus_queue.mess_q_in];
    
    		new_mess->address = BQ78350_ADDR;
    		new_mess->mess_dir = write_mess;
    		new_mess->is_block = 0;
    		new_mess->tx_cnt = length + 3;
    		new_mess->tx_data[0] = MFR_BLK_ACCESS;
    		new_mess->tx_data[1] = length;
    
    		stream[0] = (new_mess->address << 1) & ~0x01;
    		stream[1] = new_mess->tx_data[0];
    		stream[2] = new_mess->tx_data[1];
    
    		for (i = 0; i < length; i++) {
    			new_mess->tx_data[i + 2] = *data;
    			stream[i + 3] = *data;
    			data++;
    		}
    		new_mess->tx_data[length + 2] = crc8MakeBitwise(CRC8_INIT_REM,
    		CRC8_POLY, &stream[0], length + 3);
    
    		//update queue pointers
    		smbus_queue.mess_q_in++;
    		if (smbus_queue.mess_q_in == MAX_QUEUE) smbus_queue.mess_q_in = 0;
    		smbus_queue.mess_q_cnt++;
    	}
    }
    
    void smbus_writeToFlash(unsigned char *data, unsigned int length) {
    	smbus_writeBlock(data, length);
    }
    
    void smbus_read_nack(void) {
    	__no_operation();
    }
    //Return 1 if there is a message being processed.  Otherwise, returns 0.
    unsigned char smbus_process(void) {
    	//unsigned char stream[MAX_RX_LEN + MAX_TX_LEN];
    
    	if (error_flag == 1) {
    		cur_state = smbus_no_resp;
    	}
    	else if (error_flag == 2) {
    		cur_state = smbus_failure;
    	}
    
    	cur_mess = &smbus_queue.mess_q[smbus_queue.mess_q_out];
    
    	switch (cur_state) {
    	case smbus_idle:
    
    	case smbus_wait:
    		if (smbus_queue.mess_q_cnt > 0) {
    
    			if (UCB1STAT & UCBBUSY) {
    				cur_state = smbus_wait;
    			}
    			else {
    				error_flag = 0;
    				mess_done_flag = 0;
    				tx_done_flag = 0;
    				timer_delay_over = 1;
    				cur_state = smbus_delay;
    			}
    		}
    		else {
    			cur_state = smbus_idle;
    
    			return 0;
    		}
    		//break;
    
    	case smbus_delay:
    		if (timer_delay_over == 1) {
    			PTxData = (unsigned char *) (&cur_mess->tx_data[0]);
    			PRxData = (unsigned char *) (&cur_mess->rx_data[0]);
    			TXByteCtr = cur_mess->tx_cnt;
    			RXByteCtr = cur_mess->rx_cnt;
    
    			if (UCB1CTL1 & UCTXSTP) {				// Stop condition sent?
    				break;
    			}
    			cur_state = smbus_tx;				// Change state to transmit
    			TA1CTL = TIMERSMB_CLK_SRC | TACLR | TIMERSMB_IDIV_BITS | MC__UP | TAIE; // Start delay
    
    			UCB1CTL1 |= UCTR + UCTXSTT;					// Go!
    		}
    		break;
    
    	case smbus_done:
    		/*
    		 * PEC is ignored for now
    		 if (cur_mess->mess_dir == read_mess) {
    
    		 stream[0] = (UCB1I2CSA << 1) & ~0x01;
    		 stream[1] = cur_mess->address;
    		 for (i = 0; i < cur_mess->tx_cnt; i++) {
    		 stream[i + 1] = cur_mess->tx_data[i];
    		 }
    
    		 stream[cur_mess->tx_cnt] = cur_mess->address | 0x01;
    		 for (i = 0; i < cur_mess->rx_cnt; i++) {
    		 stream[i + cur_mess->tx_cnt + 1] = cur_mess->rx_data[i];
    		 }
    		 PEC = crc8MakeBitwise(CRC8_INIT_REM, CRC8_POLY, &(stream[0]),
    		 cur_mess->tx_cnt + cur_mess->rx_cnt + 2);
    		 if (PEC == *PRxData) {
    		 //update BQ78350 data for state machine
    		 //P1OUT ^= 0x01;
    		 }
    		 // else { //error in PEC }
    		 }
    		 */
    		//else { we have a tx only message }
    		if (smbus_queue.mess_q_cnt > 0) {	// Remove last message queue
    
    			if(cur_mess->mess_dir == read_mess) {
    				if(cur_mess->nack)
    					nack_cntr++;
    				//Read completed without error, jump to the callback, if there is any.
    				else if(cur_mess->rx_done_callback)
    					(cur_mess->rx_done_callback)(cur_mess->id);
    			}
    			else if(cur_mess->nack) {
    				nack_cntr++;
    			}
    
    			smbus_queue.mess_q_out++;
    			if (smbus_queue.mess_q_out == MAX_QUEUE) smbus_queue.mess_q_out = 0;
    			smbus_queue.mess_q_cnt--;
    
    		}
    		cur_state = smbus_wait;
    		break;
    
    	case smbus_tx:
    		if (tx_done_flag) cur_state = smbus_rx;
    		//drop through
    	case smbus_rx:
    		if (mess_done_flag) cur_state = smbus_done;
    		break;
    	case smbus_down:
    	case smbus_failure:
    	case smbus_no_resp:
    		//Do nothing
    		break;
    	default:
    		cur_state = smbus_wait;
    		break;
    	}
    
    	return 1;
    }
    
    unsigned int smbus_is_running(void) {
    	return (smbus_queue.mess_q_cnt > 0);
    }
    
    unsigned int smbus_get_error(void) {
    	return error_flag;
    }
    
    /*-----------------------------------------------------------------------------+
     |unsigned short crc8MakeBitwise(...)
     | IN: unsigned char CRC           => Initial crc value
     |     unsigned char Poly          => CRC polynomial
     |     unsigned int *Pmsg          => Pointer to input data stream
     |     unsigned char Msg_Size      => No. of bytes
     | OUT:unsigned short CRC          => Result of CRC function
     ------------------------------------------------------------------------------*/
    static unsigned char crc8MakeBitwise(unsigned char CRC, unsigned char Poly,
    		unsigned char *Pmsg, unsigned int Msg_Size) {
    	unsigned int i, j, carry;
    	unsigned char msg;
    
    	CRC = *Pmsg++;								// first byte loaded in "crc"
    	for (i = 0; i < Msg_Size - 1; i++) {
    		msg = *Pmsg++;							// next byte loaded in "msg"
    
    		for (j = 0; j < 8; j++) {
    			carry = CRC & 0x80;					// ckeck if MSB=1
    			CRC = (CRC << 1) | (msg >> 7);	// Shift 1 bit of next byte into crc
    			if (carry) CRC ^= Poly;				// If MSB = 1, perform XOR
    			msg <<= 1;							// Shift left msg byte by 1
    		}
    	}
    
    	// The previous loop computes the CRC of the input bit stream. To this,
    	// 8 trailing zeros are padded and the CRC of the resultant value is
    	// computed. This gives the final CRC of the input bit stream.
    	for (j = 0; j < 8; j++) {
    		carry = CRC & 0x80;
    		CRC <<= 1;
    		if (carry) CRC ^= Poly;
    	}
    
    	return (CRC);
    }
    
    /*----------------------------------------------------------------------------+
     | I2C/SMBus interrupt (USCI B1)
     +----------------------------------------------------------------------------*/
    #pragma vector = USCI_B1_VECTOR
    __interrupt
    void USCI_B1_ISR(void) {
    	switch (__even_in_range(UCB1IV, 12)) {
    	case 0:
    		break;
    	case 2:									// ALIFG
    		break;
    	case 4:									// NACKIFG
    		UCB1CTL1 |= UCTXSTP;				// Transmit a stop
    		UCB1IFG &= ~UCNACKIFG;				// Clear NACK flag
    		TA1CTL = MC__STOP;					// Turn off timeout timer
    		cur_mess->nack = 1;					//Transaction failed.  No need to wake up after ISR servicing.
    		mess_done_flag = 1;
    		break;
    	case 6:									// STTIFG
    		break;
    	case 8:									// STPIFG
    		break;
    	case 10:								// RXIFG
    		TA1CTL = MC__STOP;					// Turn off timeout timer
    		RXByteCtr--;						// Decrement RX byte counter
    
    		if (RXByteCtr) {
    			*PRxData = UCB1RXBUF;			// Multiple bytes left to receive
    			PRxData++;
    
    			//if block access, 1st byte is block length
    			RXByteCtr = (cur_mess->is_block) ? (UCB1RXBUF + 1) : RXByteCtr;
    			//reset is_block flag so length is only updated once
    			cur_mess->is_block = 0;
    
    			TA1CTL = TIMERSMB_CLK_SRC | TACLR | TIMERSMB_IDIV_BITS | MC__UP | TAIE; // Start delay
    		}
    		else {
    			*PRxData = UCB1RXBUF;				// Last byte to be received
    			mess_done_flag = 1;					// Flag to show read completed
    			__bic_SR_register_on_exit(LPM3_bits);	// Exit LPM3 since there is some processing to do after a read
    		}
    
    		if (RXByteCtr == 1)					// Only one byte left?
    		UCB1CTL1 |= UCTXSTP;				// Generate I2C stop condition
    
    											// If reading only 1 byte, stop condition
    											// should have already been sent
    		break;
    	case 12:								// TXIFG
    											// Set when UCB1TXBUF is empty
    
    		TA1CTL = MC__STOP;					// Turn off timeout timer
    		if (TXByteCtr)						// If there's something to transmit
    		{
    			UCB1TXBUF = *PTxData++;			// Load TX buffer
    			TXByteCtr--;					// Decrement TX byte counter
    			TA1CTL = TIMERSMB_CLK_SRC | TACLR | TIMERSMB_IDIV_BITS | MC__UP | TAIE; // Start delay
    		}
    		// Nothing more to transmit
    		else if (cur_mess->mess_dir == read_mess) {	//change to receive mode
    			UCB1CTL1 &= ~UCTR;				// Receiver mode
    			UCB1IFG &= ~UCTXIFG;			// Clear USCI_B0 TX int flag
    			UCB1CTL1 |= UCTXSTT;			// I2C restart (SMBus protocol)
    			tx_done_flag = 1;
    
    			TA1CTL = TIMERSMB_CLK_SRC | TACLR | TIMERSMB_IDIV_BITS | MC__UP | TAIE; // Start delay
    		}
    		else {								// Transmit only, stop transmission
    			//UCB1CTL1 &= ~UCTR;
    			UCB1IFG &= ~UCTXIFG;			// Clear USCI_B0 TX int flag
    			UCB1CTL1 |= UCTXSTP;			// Generate I2C stop condition
    
    			//cur_state = smbus_done;			// Flag to show read completed
    			mess_done_flag = 1;
    		}
    		break;
    	default:
    		break;
    	}
    }
    
    #pragma vector=TIMER1_A1_VECTOR
    __interrupt
    void TIMER1_A1_ISR(void) {
    
    	switch (__even_in_range(TA1IV, 14)) {
    	case 0:
    		break;                          // No interrupt
    	case 2:
    		TA1CTL = MC__STOP;				// Turn off timeout timer
    		TA1CCTL1 = 0;					// Disable this compare point
    		timer_delay_over = 1;			// Set flag to end delay
    		break;							// CCR1 not used
    	case 4:
    		break;							// CCR2 not used
    	case 6:
    		break;							// reserved
    	case 8:
    		break;							// reserved
    	case 10:
    		break;							// reserved
    	case 12:
    		break;							// reserved
    	case 14:							// overflow
    		TA1CTL = MC__STOP;				// Turn off timeout timer
    		UCB1CTL1 |= UCTXSTP;			// Send stop on SDA line
    
    		UCB1CTL1 |= UCSWRST;			// Enable SW reset
    		UCB1CTL1 &= ~UCSWRST;
    		UCB1IE |= UCTXIE + UCRXIE + UCNACKIE;	// Enable TX, RX, NACK interrupt
    		error_flag = 2;					// Timeout flag
    
    		break;
    	default:
    		break;
    	}
    	//__bic_SR_register_on_exit(LPM3_bits);
    }
    

    SMBus.h

    The timeout period was set to 26ms (instead of the standard 25ms since we had issues with the timeout). Also, we had to add some delays between the transmissions for the BQ78350 to be ready (this was specified in the BQ78350 TRM).

    Regards,

    Michel

  • Hello, Michel.

    Thank you very much.
    I will have a look into the codes you sent.

    Best regards,
  • Hello, Michel.

    As I mentioned earlier, we are designing a system composed by bq76940, bq78350 and MSP430. The communication with the external world will be done by the MCU via RS485 (Isolated).

    We were reading your reference designs/FAQ and we have a question about the communication/reference.

    In one of your materials it is said:

    "Low-Side Switching Considerations
    Communication with a battery over a ground referenced interface such as SMBus is typically connected to PACK-. When low side protection FETs are used, PACK- is disconnected and reference for the communication lines is lost. The communication interface will not likely work and the signals may present an un-protected leakage path for charge or discharge. Common solutions are to isolate the current paths if appropriate, switch the interface as well as the power path, isolate the interface or use high side protection FETs. The appropriate selection may vary with the application, the designer should be aware that the typical circuit or EVM schematic is not a complete product."

    Why would the MCU be referenced to PACK- instead of BATT-?

    In your reference design (10s Battery Pack Monitoring, Balancing, and Comprehensive Protection, 50A-
    www.ti.com/.../tiduar8b.pdf), the MCU is referenced to BATT-. In your bq76940EVM, the bq78350 is also referenced to BATT- and there is no isolation path to SMBus connection.

    So, do we really need to use de bq76200 or we could reference the MCU to the BATT- and isolate the RS485 communication?
    What are the design guidelines to do this?

    Thank you,
  • Hi Mauro,

    This goes beyond my knowledge as a programmer. This would be better answered by a TI employee. You could post a new question in the forums to get more visibility.

    But I can attempt to answer one question:

    Mauro Basquera said:
    So, do we really need to use de bq76200 or we could reference the MCU to the BATT- and isolate the RS485 communication?
    What are the design guidelines to do this?

    I am not sure how that relates to the reference, but the BQ769x0 serves as an analog front end; It monitors the cells, controls the FETs and .provide the protection for the system The BQ78350 communicates with the BQ759x0 through its I2C port for control and monitoring. And your MCU then fetches the information from the BQ78350.

    Regards,

    Michel

  • Ok, Michel.

    I will try in another forum.

    Thank you anyway.
  • Hello, Michel.

    Do you have the full example project using this function/library?
    I'm starting to program the MCU/bq78350 but I've no previous experience with this kind of project...

    Thanks,
  • Hi,

    Unfortunately, I cannot reveal more code.
    I have posted some more information in this thread (which also refers back to your thread), but it should help you move along with your project.

    Regards,

    Michel

  • Ok, Michel.

    I will take a look into that material.

    Thank you,