We are currently developing a system using one BQ79600 host device connected to eight BQ79616 devices in a daisy-chain configuration. Communication over the COMH line works perfectly — all modules are detected, correctly assigned unique IDs (1–8), and we can successfully read their data.
However, when we attempt to initialize and communicate through the COML line, we do receive data, but all modules report the same ID = 1 instead of unique addresses. Below are the two initialization codes we use:
-
One for COMH, which works as expected.
-
One for COML, which brings back data but with all module IDs = 1.
Additional details on the setup and behavior:
We are implementing an algorithm that alternates communication direction — reading all modules once from COML, then from COMH.
We achieve this by using two functions:
-
ReverseDirection()→ switches communication to COML -
NormalDirection()→ switches communication back to COMH
When we start the system using a COMH initialization, the direction switching mechanism works flawlessly.
We can observe on the oscilloscope that the line correctly switches from COMH → COML → COMH, and data integrity is maintained throughout.
However, if during the very first initialization (init) there is a cable disconnection or communication loss on COMH, the system still initializes, but then:
-
When we later read via COML, all module IDs return 0,
-
Whereas COMH still provides the correct module IDs (1–8).
This leads us to believe that we may need a dedicated COML-based initialization procedure for robustness, rather than starting all initializations from COMH only. We have tried adapting the initialization to COML but have not yet succeeded — all modules still report ID = 1 when initialized through COML.
Could you please review this behavior and confirm:
-
Whether a separate COML initialization procedure is required, or
-
If it is possible to perform a dual-line initialization (both COMH and COML active) to ensure proper addressing on both directions.
We would highly appreciate any insight or reference example (e.g., register initialization sequence, TI demo code section) related to address assignment through COML.
Thank you very much for your support.
void PAL_BQ79600_Init_Reverse(void)
{
BQ7961x_Modules_enum j;
PAL_BQ79600_SendWakeUpCommand();
DELAY_US(3500);//Wait at least 3.5 ms.
//Send a single device write to BQ79600-Q1 to set CONTROL1[SEND_WAKE]=1,
//which wakes up all stacked devices
PAL_BQ79600_WriteSingleDevice(MODULE_BQ79600_NOT_USED, CONTROL1, 0x20); //0x20 // A0 reverse
DELAY_US(100000);//WAKE tone duration (~1.6 ms) plus the time to enter ACTIVE mode (~10 ms)
//and multiply the result by the number of stacked BQ7961X-Q1 devices.
//(10000 + 1600) * 8 = 92800 = ~100000
PAL_BQ79600_WriteSingleDevice(MODULE_BQ79600_NOT_USED, CONTROL1, 0x80);
DELAY_US(200);
// PAL_BQ79600_WriteMultiDevices(BROADCAST, CONTROL1, 0x80); //0x01 COMH
// DELAY_US(100000U);
PAL_BQ79600_WriteMultiDevices(BROADCAST, CONTROL1, 0x81); //0x01 COMH
DELAY_US(200U);
//Set stack device address for 8 stack
for (j = MODULE_BQ79600_NOT_USED; j < BQ7961x_MODULE_MAXNUM; j++)
{
PAL_BQ79600_WriteMultiDevices(BROADCAST, DIR1_ADDR, j); //DIR0_ADDR COMH
DELAY_US(100U);
}
PAL_BQ79600_WriteMultiDevices(BROADCAST, CONTROL1, 0x80); //0x01 COMH
DELAY_US(10U);
//Stack All Devices
PAL_BQ79600_WriteMultiDevices(BROADCAST, COMM_CTRL, 0x02);
DELAY_US(10);
PAL_BQ79600_WriteSingleDevice(MODULE_BQ79600_NOT_USED, COMM_CTRL, 0x00);
DELAY_US(10);
//Set Top Stack
PAL_BQ79600_WriteSingleDevice(BQ7961x_MODULE_8, COMM_CTRL, 0x03); //BQ7961x_MODULE_8 COMH
DELAY_US(10);
// Set TSREF Enable for All Stacks
PAL_BQ79600_WriteMultiDevices(STACK, CONTROL2, 0x01);
DELAY_US(10);
//Set GPIO1-GPIO2 t ADC Input Pin for All Stacks
PAL_BQ79600_WriteMultiDevices(STACK, GPIO_CONF1, 0x12);
DELAY_US(10);
//Set GPIO3-GPIO4 t ADC Input Pin for All Stacks
PAL_BQ79600_WriteMultiDevices(STACK, GPIO_CONF2, 0x12);
DELAY_US(10);
//Set GPIO5 t ADC Input Pin for All Stacks
PAL_BQ79600_WriteMultiDevices(STACK, GPIO_CONF3, 0x02);
DELAY_US(10);
//Set Active Cell Number 11 for All Stacks
PAL_BQ79600_WriteMultiDevices(STACK, ACTIVE_CELL, 0x05);
DELAY_US(10);
//Set ADC Run Mode for All Stacks
PAL_BQ79600_WriteMultiDevices(STACK, ADC_CTRL1, 0x06);
DELAY_US(10);
//Set Balance Threshold
PAL_BQ79600_SetBalanceThreshold(thrshold);//mV
DELAY_US(10);
//Run the OV and UV round robin with all active cells
PAL_BQ79600_WriteMultiDevices(STACK,OVUV_CTRL, 0x05);
DELAY_US(10);
Uint16 comm_stat;
for (j = MODULE_BQ79600_NOT_USED; j<BQ7961x_MODULE_MAXNUM; j++)
{
comm_stat = PAL_BQ79600_ReadSingleDeviceId(j);
if(comm_stat != ERROR_CODES_SUCCESS)
{
DELAY_US(1);
}
DELAY_US(50);
}
for (j = BQ7961x_MODULE_1; j<BQ7961x_MODULE_MAXNUM; j++)
{
comm_stat = PAL_BQ79600_ReadTSREFVoltage(j);
DELAY_US(50);
}
//PAL_BQ79600_WriteMultiDevices(BROADCAST, COMM_TIMEOUT_CONF, 0x1B); // After a 10 second communication timeout, a shutdwn message is sent.
}
void PAL_BQ79600_Init(void)
{
BQ7961x_Modules_enum j;
PAL_BQ79600_SendWakeUpCommand();
DELAY_US(3500);//Wait at least 3.5 ms.
//Send a single device write to BQ79600-Q1 to set CONTROL1[SEND_WAKE]=1,
//which wakes up all stacked devices
PAL_BQ79600_WriteSingleDevice(MODULE_BQ79600_NOT_USED, CONTROL1, 0x20); //0x20 // A0 reverse
DELAY_US(100000);//WAKE tone duration (~1.6 ms) plus the time to enter ACTIVE mode (~10 ms)
//and multiply the result by the number of stacked BQ7961X-Q1 devices.
//(10000 + 1600) * 8 = 92800 = ~100000
PAL_BQ79600_WriteMultiDevices(BROADCAST, CONTROL1, 0x01); //0x01 COMH
DELAY_US(100U);
//Set stack device address for 8 stack
for (j = MODULE_BQ79600_NOT_USED; j < BQ7961x_MODULE_MAXNUM; j++)
{
PAL_BQ79600_WriteMultiDevices(BROADCAST, DIR0_ADDR, j); //DIR0_ADDR COMH
DELAY_US(100U);
}
PAL_BQ79600_WriteSingleDevice(MODULE_BQ79600_NOT_USED, COMM_CTRL, 0x00);
DELAY_US(10);
//Stack All Devices
PAL_BQ79600_WriteMultiDevices(BROADCAST, COMM_CTRL, 0x02);
DELAY_US(10);
//Set Top Stack
PAL_BQ79600_WriteSingleDevice(BQ7961x_MODULE_8, COMM_CTRL, 0x03); //BQ7961x_MODULE_8 COMH
DELAY_US(10);
// Set TSREF Enable for All Stacks
PAL_BQ79600_WriteMultiDevices(STACK, CONTROL2, 0x01);
DELAY_US(10);
//Set GPIO1-GPIO2 t ADC Input Pin for All Stacks
PAL_BQ79600_WriteMultiDevices(STACK, GPIO_CONF1, 0x12);
DELAY_US(10);
//Set GPIO3-GPIO4 t ADC Input Pin for All Stacks
PAL_BQ79600_WriteMultiDevices(STACK, GPIO_CONF2, 0x12);
DELAY_US(10);
//Set GPIO5 t ADC Input Pin for All Stacks
PAL_BQ79600_WriteMultiDevices(STACK, GPIO_CONF3, 0x02);
DELAY_US(10);
//Set Active Cell Number 11 for All Stacks
PAL_BQ79600_WriteMultiDevices(STACK, ACTIVE_CELL, 0x05);
DELAY_US(10);
//Set ADC Run Mode for All Stacks
PAL_BQ79600_WriteMultiDevices(STACK, ADC_CTRL1, 0x06);
DELAY_US(10);
//Set Balance Threshold
PAL_BQ79600_SetBalanceThreshold(thrshold);//mV
DELAY_US(10);
//Run the OV and UV round robin with all active cells
PAL_BQ79600_WriteMultiDevices(STACK,OVUV_CTRL, 0x05);
DELAY_US(10);
Uint16 comm_stat;
for (j = MODULE_BQ79600_NOT_USED; j<BQ7961x_MODULE_MAXNUM; j++)
{
comm_stat = PAL_BQ79600_ReadSingleDeviceId(j);
if(comm_stat != ERROR_CODES_SUCCESS)
{
DELAY_US(1);
}
DELAY_US(50);
}
for (j = BQ7961x_MODULE_1; j<BQ7961x_MODULE_MAXNUM; j++)
{
comm_stat = PAL_BQ79600_ReadTSREFVoltage(j);
DELAY_US(50);
}
//PAL_BQ79600_WriteMultiDevices(BROADCAST, COMM_TIMEOUT_CONF, 0x1B); // After a 10 second communication timeout, a shutdwn message is sent.
}
Uint16 PAL_BQ79600_ReverseDirection()
{
BQ7961x_Modules_enum j;
static Uint16 dir1_addr_done = 0;
// PAL_BQ79600_WriteSingleDevice(BQ7961x_MODULE_1, COMM_CTRL, 0x02); // STACK_DEV
// PAL_BQ79600_WriteSingleDevice(BQ7961x_MODULE_8, COMM_CTRL, 0x02);
// DELAY_US(50);
PAL_BQ79600_WriteSingleDevice(MODULE_BQ79600_NOT_USED, CONTROL1, 0x80); // change base device direction
DELAY_US(10);
// PAL_BQ79600_WriteSingleDevice(BQ7961x_MODULE_8, COMM_CTRL, 0x02);
// DELAY_US(10);
PAL_BQ79600_WriteMultiDevices(REVERSE, COMM_CTRL, 0x02);
DELAY_US(10);
PAL_BQ79600_WriteMultiDevices(REVERSE, CONTROL1, 0x80); //change the stack device direction
DELAY_US(2000);
if (!dir1_addr_done)
{
PAL_BQ79600_WriteMultiDevices(BROADCAST, CONTROL1, 0x81);
DELAY_US(10);
for (j = BQ7961x_MODULE_MAXNUM; j > MODULE_BQ79600_NOT_USED; j--)
{
PAL_BQ79600_WriteMultiDevices(BROADCAST, DIR1_ADDR, j);
DELAY_US(10);
}
PAL_BQ79600_WriteSingleDevice(MODULE_BQ79600_NOT_USED, COMM_CTRL, 0x00);
DELAY_US(10);
PAL_BQ79600_WriteMultiDevices(BROADCAST, COMM_CTRL, 0x02); // STACK_DEV
DELAY_US(10);
dir1_addr_done = 1;
}
PAL_BQ79600_WriteSingleDevice(BQ7961x_MODULE_1, COMM_CTRL, 0x03); // ToS=1
DELAY_US(10);
return ERROR_CODES_REVERSE_DIRECTION;
}
Uint16 PAL_BQ79600_SendNormalDirectionCommand()
{
static Uint16 dir0_addr_done = 0;
BQ7961x_Modules_enum j;
// PAL_BQ79600_WriteSingleDevice(BQ7961x_MODULE_1, COMM_CTRL, 0x02);
// PAL_BQ79600_WriteSingleDevice(BQ7961x_MODULE_8, COMM_CTRL, 0x02);
PAL_BQ79600_WriteSingleDevice(MODULE_BQ79600_NOT_USED, CONTROL1, 0x00); // change base device direction
DELAY_US(10);
// PAL_BQ79600_WriteSingleDevice(BQ7961x_MODULE_8, COMM_CTRL, 0x02);
// DELAY_US(10);
PAL_BQ79600_WriteMultiDevices(REVERSE, COMM_CTRL, 0x02);
DELAY_US(10);
PAL_BQ79600_WriteMultiDevices(REVERSE, CONTROL1, 0x01); //change the stack device direction
DELAY_US(2000);
if (!dir0_addr_done)
{
//EnableAutoAddressing
PAL_BQ79600_WriteMultiDevices(BROADCAST, CONTROL1, 0x01);
DELAY_US(10);
// Set stack device address for 8 stack
for (j = MODULE_BQ79600_NOT_USED; j < BQ7961x_MODULE_MAXNUM; j++)
{
PAL_BQ79600_WriteMultiDevices(BROADCAST, DIR0_ADDR, j);
DELAY_US(10);
}
PAL_BQ79600_WriteSingleDevice(MODULE_BQ79600_NOT_USED, COMM_CTRL, 0x00);
DELAY_US(10);
//Stack All Devices
PAL_BQ79600_WriteMultiDevices(BROADCAST, COMM_CTRL, 0x02);
DELAY_US(10);
dir0_addr_done = 1;
}
//Set Top Stack
PAL_BQ79600_WriteSingleDevice(BQ7961x_MODULE_8, COMM_CTRL, 0x03);
DELAY_US(10);
return 0;
}
buradan hareketle bq coml initi yapmam gerektiğini de düşündüm ancak başarılı olamadım bana detaylı geri dönüş yaparsanız cok sevinirim