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.

[参考译文] BQ79616:BQ 菊花链

Guru**** 2442090 points
Other Parts Discussed in Thread: BQ79616, MSP430FR5962, HALCOGEN, CODECOMPOSER

请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/power-management-group/power-management/f/power-management-forum/1122756/bq79616-bq-daisy-chain

器件型号:MSP430FR5994
主题中讨论的其他器件:MSP430FR5962HALCOGENCODECOMPOSER

我测试了连接到 BQ79600和 MSP430 (定制 PCB 上的 SPI 接口)的3个定制 BQ79616 MBB 菊花链。 其中一个 MBB (菊花链中间的器件2)在过去的 ESD 测试中损坏了 COMH 接口。 当 MBBS 堆栈连接到 BQ GUI 时,将检测到正确数量的正常运行的堆栈设备,并且自动寻址序列完成。 然而、只有当提供了正常运行的电路板数量时、MSP430固件才完成自动寻址。 如果 TOTALBOARDS 包括 COMH 接口损坏的 MBB、MISO 线路无活动、保持在0xff。 我不知道 BQ79616中缺少任何寄存器设置。 我可以做些什么来进一步解决这个问题--我没有将跳线焊接到 MBB 的 COML 线路上。

当堆栈包含 COMH 接口损坏的 MBB 时、唤醒似乎正确完成。 SPI_RDY 变为高电平有效、然后自动寻址不再继续。

随附的是在 TOTALBOARDS 设置为3 (2个完全有效的 MBB)的情况下自动地址成功完成时的屏幕截图。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Priya、

    MCU 软件仅在根据所连接的内容给出适当的 TALBOARD 变量时才能正常工作。 这是预期行为。

    此致、

    泰勒

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    泰勒

    如果 菊花链中的 BQ79616损坏、自动寻址序列应能够向 BMS 报告正确数量的正常运行的 MBB (79616)。 这样、技术人员就知道堆栈中要首先检查和替换的 MBB。 例如、如果10菊花链中的 MBB 3不起作用、则自动寻址应检测到3个正常工作的 MBB 堆栈、但包含 BRIDGEDEVICE 的 TOTALBOARDS 为11。 BQ GUI 能够执行此操作、固件也应该执行此操作。 我将焊接带跳线的 MBB、我将在两周内研究信号。 如果我缺少一些东西、请告诉我。

    Priya

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我在连接  到 BQ79600的20x BQ79616器件 (使用 SPI)中遇到了同样的问题

    它需要在"spI.c"->中进行多处更改、例如 spiTransmitAndReceiveData

            while(((spi->FLG & 0x00000100U) != 0x00000100U) && avoidEndlessLoop < 50000) // 500ms
            {
                avoidEndlessLoop++;
                delayus(10);
            } /* Wait */
    
            if(avoidEndlessLoop >= 50000) break;

    我们解决这个问题的方法是解决20、19、18、...直到我们有一组有效的器件;
    ((每次更改"TOTALBOARDS")
    切换到南桥并再次开始寻址:20-(有效)、20-(有效)-1、...直到我们在另一侧有一个有效的设置

    您可以将结果压缩成一根断裂的导线(或 MBB 或多根导线)

    如果有更简单的方法,我很想听到它:-)

    此致、
    Collin

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Collin、

    感谢你的答复。 如果自动地址序列第一次失败、我尝试重复该序列。 它似乎对 MISO 值没有影响。 我有一个称为 MAXBOARDS 的定义、用于分配容纳 BQ 响应帧的数组。 TOTALBOARDS 是一个 uint8_t 变量、当自动寻址未按预期完成时、我会递减该变量。spiCommands.c 使用 TOTALBOARDS 计算响应字节的长度。  但是、我对无限循环没有任何检查。 您在项目中使用的是什么 MCU? 我们使用 MSP430FR5962。 如果我将 MAXBOARDS 设置为4、MISO 始终为0xff;但实际工作板的数量仅为3。  

    如果 MAXBOARDS 和 TOTALBOARDS 都设置为3、则自动寻址完成。 我可以使用有关其他方法的指针来跟踪问题发生的位置。  

    #define Bridge_DEV_CONF1_Response      0x14
    //Auto_addr response value
    extern uint8_t TOTALBOARDS;
    
    uint16_t autoaddr_response_frame[(1+6)*MAXBOARDS];
    
    uint8_t currentBoard;
    uint16_t bq79600Addr = 0;
    
    
    void SpiWake79600(void)
    {
        BQSPI_CS_REG  &= ~BQSPI_CS_PIN;
        delay_us(2);
        BQSPI_MOSI_REG &= ~BQSPI_MOSI_PIN;
        delay_ms(2.75);                                          // WAKE ping = 2.8ms
        BQSPI_MOSI_REG = BQSPI_MOSI_PIN;
        delay_us(2);
        BQSPI_MOSI_REG = BQSPI_MOSI_PIN;
        BQSPI_CS_REG  = BQSPI_CS_PIN;
    
        BQ_PERIPH_MOD_FUNC_SELECT |= (BQSPI_MOSI_PIN | BQSPI_MISO_PIN | BQSPI_CLK);
    
    }
    
    
    
    void SpiAutoAddress(void)
    {
        //DUMMY WRITE TO SNCHRONIZE ALL DAISY CHAIN DEVICES DLL (IF A DEVICE RESET OCCURED PRIOR TO THIS)
        SpiWriteReg(0, OTP_ECC_DATAIN1, 0X00, 1, FRMWRT_STK_W);
        SpiWriteReg(0, OTP_ECC_DATAIN2, 0X00, 1, FRMWRT_STK_W);
        SpiWriteReg(0, OTP_ECC_DATAIN3, 0X00, 1, FRMWRT_STK_W);
        SpiWriteReg(0, OTP_ECC_DATAIN4, 0X00, 1, FRMWRT_STK_W);
        SpiWriteReg(0, OTP_ECC_DATAIN5, 0X00, 1, FRMWRT_STK_W);
        SpiWriteReg(0, OTP_ECC_DATAIN6, 0X00, 1, FRMWRT_STK_W);
        SpiWriteReg(0, OTP_ECC_DATAIN7, 0X00, 1, FRMWRT_STK_W);
        SpiWriteReg(0, OTP_ECC_DATAIN8, 0X00, 1, FRMWRT_STK_W);
    
        //ENABLE AUTO ADDRESSING MODE
        SpiWriteReg(0, CONTROL1, 0X01, 1, FRMWRT_ALL_W);
    
        //SET ADDRESSES FOR EVERY BOARD
        for(currentBoard=0; currentBoard<TOTALBOARDS; currentBoard++)
        {
            SpiWriteReg(0, DIR0_ADDR, currentBoard, 1, FRMWRT_ALL_W);
        }
        //BROADCAST WRITE TO SET ALL DEVICES AS STACK DEVICE
        SpiWriteReg(0, COMM_CTRL, 0x02, 1, FRMWRT_ALL_W);
    
        //SET THE HIGHEST DEVICE IN THE STACK AS BOTH STACK AND TOP OF STACK
        SpiWriteReg(TOTALBOARDS-1, COMM_CTRL, 0x03, 1, FRMWRT_SGL_W);
    
        //SYNCRHONIZE THE DLL WITH A THROW-AWAY READ
        SpiReadReg(0, OTP_ECC_DATAIN1, autoaddr_response_frame, 1, FRMWRT_STK_R);
        SpiReadReg(0, OTP_ECC_DATAIN2, autoaddr_response_frame, 1, FRMWRT_STK_R);
        SpiReadReg(0, OTP_ECC_DATAIN3, autoaddr_response_frame, 1, FRMWRT_STK_R);
        SpiReadReg(0, OTP_ECC_DATAIN4, autoaddr_response_frame, 1, FRMWRT_STK_R);
        SpiReadReg(0, OTP_ECC_DATAIN5, autoaddr_response_frame, 1, FRMWRT_STK_R);
        SpiReadReg(0, OTP_ECC_DATAIN6, autoaddr_response_frame, 1, FRMWRT_STK_R);
        SpiReadReg(0, OTP_ECC_DATAIN7, autoaddr_response_frame, 1, FRMWRT_STK_R);
        SpiReadReg(0, OTP_ECC_DATAIN8, autoaddr_response_frame, 1, FRMWRT_STK_R);
    
        //OPTIONAL: read back all device addresses
        for(currentBoard=0; currentBoard<TOTALBOARDS; currentBoard++)
        {
            SpiReadReg(currentBoard, DIR0_ADDR, autoaddr_response_frame, 1, FRMWRT_SGL_R);
        }
    
        //OPTIONAL: read register address 0x2001 and verify that the value is 0x14
        SpiReadReg(0, Bridge_DEV_CONF1, autoaddr_response_frame, 1, FRMWRT_SGL_R);
        bq79600Addr = autoaddr_response_frame[4];
    
       return;
    }
    
    
    
    void SpiReadyComm(void)
    {
    
        while (bq79600Addr != 0x14){
    
            SpiWake79600();                                           //wake up BQ79600
            delay_ms(3.5);
    
            SpiWriteReg(0, CONTROL1, 0x20, 1, FRMWRT_SGL_W);                     //wake up BQ79616
            delay_ms(11.6*MAXBOARDS);
    
            SpiAutoAddress();                                         //start auto address for BQ79600 and BQ79616
            if (bq79600Addr != 0x14)
               TOTALBOARDS--;
        }
    
    
    e2e.ti.com/.../spiCommands.c

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我们使用的是 ARM Cortex R4 -> TMS_LaunchPad_RM46 (TMS570LS12)

    TOLBOARDS-Part 确实有点令人困惑...最后我们给出 了 SpiAutoAddress 的一些参数。

    int SpiAutoAddress(int debug, uint16 direction, uint8 noOfDevicesToWake)
    {
        int returnValue = 0;
    
        //DUMMY WRITE TO SNCHRONIZE ALL DAISY CHAIN DEVICES DLL (IF A DEVICE RESET OCCURED PRIOR TO THIS)
        returnValue = SpiWriteReg(0, OTP_ECC_DATAIN1, 0X00, 1, FRMWRT_STK_W);
        if(debug==1) printf("BQ79616L125: %d\n", returnValue); if(returnValue < -900) return returnValue;
        returnValue = SpiWriteReg(0, OTP_ECC_DATAIN2, 0X00, 1, FRMWRT_STK_W);
        if(debug==1) printf("BQ79616L127: %d\n", returnValue); if(returnValue < -900) return returnValue;
        returnValue = SpiWriteReg(0, OTP_ECC_DATAIN3, 0X00, 1, FRMWRT_STK_W);
        if(debug==1) printf("BQ79616L129: %d\n", returnValue); if(returnValue < -900) return returnValue;
        returnValue = SpiWriteReg(0, OTP_ECC_DATAIN4, 0X00, 1, FRMWRT_STK_W);
        if(debug==1) printf("BQ79616L131: %d\n", returnValue); if(returnValue < -900) return returnValue;
        returnValue = SpiWriteReg(0, OTP_ECC_DATAIN5, 0X00, 1, FRMWRT_STK_W);
        if(debug==1) printf("BQ79616L133: %d\n", returnValue); if(returnValue < -900) return returnValue;
        returnValue = SpiWriteReg(0, OTP_ECC_DATAIN6, 0X00, 1, FRMWRT_STK_W);
        if(debug==1) printf("BQ79616L135: %d\n", returnValue); if(returnValue < -900) return returnValue;
        returnValue = SpiWriteReg(0, OTP_ECC_DATAIN7, 0X00, 1, FRMWRT_STK_W);
        if(debug==1) printf("BQ79616L137: %d\n", returnValue); if(returnValue < -900) return returnValue;
        returnValue = SpiWriteReg(0, OTP_ECC_DATAIN8, 0X00, 1, FRMWRT_STK_W);
        if(debug==1) printf("BQ79616L139: %d\n", returnValue); if(returnValue < -900) return returnValue;
    
        switch(direction)
        {
        case DIR0_ADDR: // North
            returnValue = SpiWriteReg(0, CONTROL1, 0x00, 1, FRMWRT_ALL_W);      // Set the complete stack to forward direction
            if(debug==1) printf("BQ79616L145: %d\n", returnValue); if(returnValue < -900) break;
            break;
        case DIR1_ADDR: // South
            returnValue = SpiWriteReg(0, CONTROL1, 0x80, 1, FRMWRT_REV_ALL_W);  // Set the complete stack to reverse direction
            if(debug==1) printf("BQ79616L149: %d\n", returnValue); if(returnValue < -900) break;
            break;
        }
    
        //BROADCAST WRITE TO SET ALL DEVICES AS STACK DEVICE
        returnValue = SpiWriteReg(0, COMM_CTRL, 0x02, 1, FRMWRT_ALL_W);
        if(debug==1) printf("BQ79616L155: %d\n", returnValue); if(returnValue < -900) return returnValue;
    
        //ENABLE AUTO ADDRESSING MODE
        switch(direction)
        {
        case DIR0_ADDR: // North
            returnValue = SpiWriteReg(0, CONTROL1, 0X01, 1, FRMWRT_ALL_W); // ADDR_WR 1; North: 0x01 South: 0x81
            if(debug==1) printf("BQ79616L143: %d\n", returnValue); if(returnValue < -900) return returnValue;
            break;
        case DIR1_ADDR: // South
            returnValue = SpiWriteReg(0, CONTROL1, 0X81, 1, FRMWRT_ALL_W); // ADDR_WR 1; North: 0x01 South: 0x81
            if(debug==1) printf("BQ79616L143: %d\n", returnValue); if(returnValue < -900) return returnValue;
            break;
        }
    
        //SET ADDRESSES FOR EVERY BOARD
        for(currentBoard=0; currentBoard<noOfDevicesToWake+1; currentBoard++)
        {
            returnValue = SpiWriteReg(0, direction, currentBoard, 1, FRMWRT_ALL_W);  // direction: "InitNorth" DIR0_ADDR  // "InitSouth" DIR1_ADDR
            if(debug==1) printf("BQ79616L149: %d - %d\n", returnValue, currentBoard);  if(returnValue < -900) return returnValue;
        }
    
        //BROADCAST WRITE TO SET ALL DEVICES AS STACK DEVICE
        returnValue = SpiWriteReg(0, COMM_CTRL, 0x02, 1, FRMWRT_ALL_W);
        if(debug==1) printf("BQ79616L155: %d\n", returnValue); if(returnValue < -900) return returnValue;
    
        //SET THE HIGHEST DEVICE IN THE STACK AS BOTH STACK AND TOP OF STACK
        returnValue = SpiWriteReg(noOfDevicesToWake, COMM_CTRL, 0x03, 1, FRMWRT_SGL_W);
        if(debug==1) printf("BQ79616L158: %d\n", returnValue); if(returnValue < -900) return returnValue;
    
        //SYNCRHONIZE THE DLL WITH A THROW-AWAY READ
        returnValue = SpiReadReg(0, OTP_ECC_DATAIN1, autoaddr_response_frame, 1, 0, FRMWRT_STK_R, noOfDevicesToWake);
        if(debug==1) printf("BQ79616L162: %d\n", returnValue); if(returnValue < -900) return returnValue;
        returnValue = SpiReadReg(0, OTP_ECC_DATAIN2, autoaddr_response_frame, 1, 0, FRMWRT_STK_R, noOfDevicesToWake);
        if(debug==1) printf("BQ79616L164: %d\n", returnValue); if(returnValue < -900) return returnValue;
        returnValue = SpiReadReg(0, OTP_ECC_DATAIN3, autoaddr_response_frame, 1, 0, FRMWRT_STK_R, noOfDevicesToWake);
        if(debug==1) printf("BQ79616L166: %d\n", returnValue); if(returnValue < -900) return returnValue;
        returnValue = SpiReadReg(0, OTP_ECC_DATAIN4, autoaddr_response_frame, 1, 0, FRMWRT_STK_R, noOfDevicesToWake);
        if(debug==1) printf("BQ79616L168: %d\n", returnValue); if(returnValue < -900) return returnValue;
        returnValue = SpiReadReg(0, OTP_ECC_DATAIN5, autoaddr_response_frame, 1, 0, FRMWRT_STK_R, noOfDevicesToWake);
        if(debug==1) printf("BQ79616L170: %d\n", returnValue); if(returnValue < -900) return returnValue;
        returnValue = SpiReadReg(0, OTP_ECC_DATAIN6, autoaddr_response_frame, 1, 0, FRMWRT_STK_R, noOfDevicesToWake);
        if(debug==1) printf("BQ79616L172: %d\n", returnValue); if(returnValue < -900) return returnValue;
        returnValue = SpiReadReg(0, OTP_ECC_DATAIN7, autoaddr_response_frame, 1, 0, FRMWRT_STK_R, noOfDevicesToWake);
        if(debug==1) printf("BQ79616L174: %d\n", returnValue); if(returnValue < -900) return returnValue;
        returnValue = SpiReadReg(0, OTP_ECC_DATAIN8, autoaddr_response_frame, 1, 0, FRMWRT_STK_R, noOfDevicesToWake);
        if(debug==1) printf("BQ79616L176: %d\n", returnValue); if(returnValue < -900) return returnValue;
    
        //OPTIONAL: read back all device addresses
        for(currentBoard=0; currentBoard<noOfDevicesToWake+1; currentBoard++)
        {
            returnValue = SpiReadReg(currentBoard, direction, autoaddr_response_frame, 1, 0, FRMWRT_SGL_R, noOfDevicesToWake);  // direction: "InitNorth" DIR0_ADDR  // "InitSouth" DIR1_ADDR
            if(debug==1) printf("BQ79616L182: %d - %d\n", returnValue, currentBoard); if(returnValue < -900) return returnValue;
        }
    
        //OPTIONAL: read register address 0x2001 and verify that the value is 0x14
        returnValue = SpiReadReg(0, 0x2001, autoaddr_response_frame, 1, 0, FRMWRT_SGL_R, noOfDevicesToWake);
        if(debug==1) printf("BQ79616L187: %d\n", returnValue); if(returnValue < -900) return returnValue;
    
       return returnValue;
    }
    

    我们搜索 了导致无限循环的所有代码、并使这些器件返回的值低于-900。
    之前这些 while{}循环导致了120秒 的冻结、然后电路板上的看门狗重新启动。 (再次选中"spi.c")
    您要传输的代码实际上与"HALCoGen"自动生成的代码完全不同。
    嗯,我们还做了一些(提到的)修改:-)

    /** @fn uint32 spiTransmitData(spiBASE_t *spi, spiDAT1_t *dataconfig_t, uint32 blocksize, uint16 * srcbuff)
    *   @brief Transmits Data using polling method
    *   @param[in] spi           - Spi module base address
    *   @param[in] dataconfig_t    - Spi DAT1 register configuration
    *   @param[in] blocksize    - number of data
    *   @param[in] srcbuff        - Pointer to the source data ( 16 bit).
    *
    *   @return flag register value.
    *
    *   This function transmits blocksize number of data from source buffer using polling method.
    */
    /* SourceId : SPI_SourceId_005 */
    /* DesignId : SPI_DesignId_005 */
    /* Requirements : HL_SR131 */
    int spiTransmitData(spiBASE_t *spi, spiDAT1_t *dataconfig_t, uint32 blocksize, uint16 * srcbuff)
    {
        volatile uint32 SpiBuf;
        uint16 Tx_Data;
        uint32 Chip_Select_Hold = (dataconfig_t->CS_HOLD) ? 0x10000000U : 0U;
        uint32 WDelay = (dataconfig_t->WDEL) ? 0x04000000U : 0U;
        SPIDATAFMT_t DataFormat = dataconfig_t->DFSEL;
        uint8 ChipSelect = dataconfig_t->CSNR;
    
        int avoidEndlessLoop = 0;
    
        while(blocksize != 0U)
        {
            if((spi->FLG & 0x000000FFU) !=0U)
            {
               break;
            }
    
            if(blocksize == 1U)
            {
               Chip_Select_Hold = 0U;
            }
            /*SAFETYMCUSW 45 D MR:21.1 <APPROVED> "Valid non NULL input parameters are only allowed in this driver" */
            Tx_Data = *srcbuff;
    
            spi->DAT1 =  ((uint32)DataFormat << 24U) |
                         ((uint32)ChipSelect << 16U) |
                         (WDelay)           |
                         (Chip_Select_Hold) |
                         (uint32)Tx_Data;
            /*SAFETYMCUSW 567 S MR:17.1,17.4 <APPROVED> "Pointer increment needed" */
            srcbuff++;
            /*SAFETYMCUSW 28 D MR:NA <APPROVED> "Hardware status bit read check" */
            while(((spi->FLG & 0x00000100U) != 0x00000100U) && avoidEndlessLoop < 50000) // 500ms
            {
                avoidEndlessLoop++;
                delayus(10);
            } /* Wait */
            if(avoidEndlessLoop >= 50000) break;
    
            SpiBuf = spi->BUF;
    
            blocksize--;
        }
    
        if(avoidEndlessLoop >= 50000) return -953; // Error spiTransmitData
        return (spi->FLG & 0xFFU);
    }

    希望 您可以使用其中的一些功能。 此致、Collin

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Collin -

    感谢您的回复。 您的 spiReadReg 函数如何使用 noOfDevicesToWake? 何时更新此参数?

    Priya

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Collin、

    感谢您的响应、是的、我们当前使用的方法是 TALBOAD 变量。 如果您可以进一步评论以帮助您对上述参数 mod 进行 Priya、请不胜感激。

    此致、

    泰勒

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我意识到需要重新初始化 SPI、并在唤醒后定义外设模块 SPI 引脚功能、作为重复自动寻址的一部分、直到成功。 它终于开始工作了!  

    感谢你的帮助。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    很高兴听到这个消息、很抱歉耽误我的时间。
    我总是需要重新启动 Mac (到 Windows)才能访问 CodeComposer 项目,因此有时我可以阅读帖子,但没有回复的基础:-/

    关于上一个问题、基本上在 TALBOARDS 使用的任何地方、我都用参数替换了它。  

    另一个提示:我使用"用户代码开始"和"用户代码结束"块、通过使用将自动生成的器件替换为我的代码
    #if 0和#endif 语句。 使用此工具、我能够反复生成 HALCoGen 代码、而不会丢失我的修改。

    int spiTransmitAndReceiveData(spiBASE_t *spi, spiDAT1_t *dataconfig_t, uint32 blocksize, uint16 * srcbuff, uint16 * destbuff)
    {
        ... HALCoGen variables ...
    
    /* USER CODE BEGIN (14) */
        ... my code ...
    #if 0
    /* USER CODE END */
    
        ... HALCoGen code ...
        
    /* USER CODE BEGIN (15) */
    #endif
        ... my code ...
    /* USER CODE END */
    }


    当我使用 CAN 控制器和以太网扩展 SPI 桥接器时、这非常方便。
    每次我修改电路板设置时、HALCoGen 都会覆盖所有不在用户代码块中的内容。

    此致 Collin

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Collin、

    感谢您的帮助!

    此致、

    泰勒