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.

TPS65381 DIAG_OUT is always zero



Hello,

We are using the TPS65381 power chip with an RM48L952ZWT on a board designed in house. We have the Q+A watchdog working consistently and hold ENDRV high, so SPI works and the device seemed to be powered properly. I am attempting to use the DIAG_OUT to monitor the various analog MUX signals and I get a value of zero regardless of which signal I select. The DIAG_OUT pin is wired to the ADC of the RM48, and we have confirmed that the ADC works properly with other signals. Putting a probe on the DIAG_OUT pin shows a 0 voltage at all times.

I had tested the Diag-ADC functionality on the RM48-HDK early on (using the TPS65381-EVM)) and it worked fine, so I am pretty confident that my code is right. Here is a representative snippet of the code. I am using ADC2 Group 1 with DIAG_OUT connected to ADC2 channel 0.

adcData_t ADC_Data[6] = {0};
spiInit();
ecmpInit();
adcInit();
ecmpDiagMuxOutputMode(ECMP_DIAG_MUX_MODE_ANSLOG); // set output mode to analog
ecmpDiagMuxEnable();
ecmpDiagMuxSelectSignal(ECMP_DIAG_MUX_ANSLOG_VDD5); // VDD5 regulator output
xTaskDelay(100/configTICK_RATE_MS); // 100 ms delay
adcStartConversion(adcREG2, adcGROUP1);
while((adcIsConversionComplete(adcREG2, adcGROUP1))==0);
adcGetData(adcREG2, adcGROUP1, ADC_Data);

The 5 ADC channels connected to other signals yield valid digital results but channel 0, the DIAG_OUT pin, always shows digital value somewhere between 0 and maybe 7, yielding an analog value < 0.01. I have also tried using Digital MUX mode, reading several of the Digital MUX signals and I also see a zero value there.

Additionally, we lifted the DIAG_OUT pin off of the board and confirmed that it was showing 0v while muxing through the different analog signals.

Can you think of any reasons the DIAG_OUT signal would behave this way?

Thanks,
Bobby Goldberg

  • Bobby,

    I think this pin driven strength is really weak. Any pull downs will kill the result. And you must reserve enough ADC sampling time.

    Can you send the spiInit() function? I would check a few parameters.

    If it does not solve your problem, let me know. I take tomorrow off. But Friday, I will be back in office.

    Thanks,

    Haixiao

  • Hi Haixiao,

    I don't believe there are any pull downs.  In fact, as I mentioned, while cycling through the mux'd analog signals in my code, and with the DIAG_OUT pin completely disconnected from the board, a probe of that pin showed no signal at all.

    Thanks,

    Bobby

    Here is spiInit():

    void spiInit(void)
    {
    /* USER CODE BEGIN (2) */
    taskENTER_CRITICAL();
    /* USER CODE END */

    /** @b initialize @b SPI2 */

    /** bring SPI out of reset */
    spiREG2->GCR0 = 1U;

    /** SPI2 master mode and clock configuration */
    spiREG2->GCR1 = (spiREG2->GCR1 & 0xFFFFFFFCU) | ((1U << 1U) /* CLOKMOD */
    | 1U); /* MASTER */

    /** SPI2 enable pin configuration */
    spiREG2->INT0 = (spiREG2->INT0 & 0xFEFFFFFFU)| (0U << 24U); /* ENABLE HIGHZ */

    /** - Delays */
    spiREG2->DELAY = (8U << 24U) /* C2TDELAY */
    | (9U << 16U) /* T2CDELAY */
    | (0U << 8U) /* T2EDELAY */
    | 0U; /* C2EDELAY */

    /** - Data Format 0 */
    spiREG2->FMT0 = (103U << 24U) /* wdelay */
    | (0U << 23U) /* parity Polarity */
    | (0U << 22U) /* parity enable */
    | (0U << 21U) /* wait on enable */
    | (0U << 20U) /* shift direction */
    | (0U << 17U) /* clock polarity */
    | (0U << 16U) /* clock phase */
    | (219U << 8U) /* baudrate prescale */
    | 16U; /* data word length */
    /** - Data Format 1 */
    spiREG2->FMT1 = (103U << 24U) /* wdelay */
    | (0U << 23U) /* parity Polarity */
    | (0U << 22U) /* parity enable */
    | (0U << 21U) /* wait on enable */
    | (0U << 20U) /* shift direction */
    | (0U << 17U) /* clock polarity */
    | (0U << 16U) /* clock phase */
    | (219U << 8U) /* baudrate prescale */
    | 16U; /* data word length */

    /** - Data Format 2 */
    spiREG2->FMT2 = (103U << 24U) /* wdelay */
    | (0U << 23U) /* parity Polarity */
    | (0U << 22U) /* parity enable */
    | (0U << 21U) /* wait on enable */
    | (0U << 20U) /* shift direction */
    | (0U << 17U) /* clock polarity */
    | (0U << 16U) /* clock phase */
    | (219U << 8U) /* baudrate prescale */
    | 16U; /* data word length */

    /** - Data Format 3 */
    spiREG2->FMT3 = (103U << 24U) /* wdelay */
    | (0U << 23U) /* parity Polarity */
    | (0U << 22U) /* parity enable */
    | (0U << 21U) /* wait on enable */
    | (0U << 20U) /* shift direction */
    | (0U << 17U) /* clock polarity */
    | (0U << 16U) /* clock phase */
    | (219U << 8U) /* baudrate prescale */
    | 16U; /* data word length */

    /** - set interrupt levels */
    spiREG2->LVL = (1U << 9U) /* TXINT */
    | (1U << 8U) /* RXINT */
    | (0U << 6U) /* OVRNINT */
    | (0U << 4U) /* BITERR */
    | (0U << 3U) /* DESYNC */
    | (0U << 2U) /* PARERR */
    | (0U << 1U) /* TIMEOUT */
    | (0U); /* DLENERR */

    /** - clear any pending interrupts */
    spiREG2->FLG |= 0xFFFFU;

    /** - enable interrupts */
    spiREG2->INT0 = (spiREG2->INT0 & 0xFFFF0000U)
    | (0U << 9U) /* TXINT */
    | (0U << 8U) /* RXINT */
    | (1U << 6U) /* OVRNINT */
    | (1U << 4U) /* BITERR */
    | (1U << 3U) /* DESYNC */
    | (1U << 2U) /* PARERR */
    | (1U << 1U) /* TIMEOUT */
    | (1U); /* DLENERR */

    /** @b initialize @b SPI2 @b Port */

    /** - SPI2 Port output values */
    spiREG2->PC3 = 0U /* SCS[0] */
    | (0U << 1U) /* SCS[1] */
    | (0U << 8U) /* ENA */
    | (0U << 9U) /* CLK */
    | (0U << 10U) /* SIMO */
    | (0U << 11U); /* SOMI */

    /** - SPI2 Port direction */
    spiREG2->PC1 = 1U /* SCS[0U] */
    | (1U << 1U) /* SCS[1U] */
    | (1U << 8U) /* ENA */
    | (1U << 9U) /* CLK */
    | (1U << 10U) /* SIMO */
    | (0U << 11U); /* SOMI */

    /** - SPI2 Port open drain enable */
    spiREG2->PC6 = 0U /* SCS[0U] */
    | (0U << 1U) /* SCS[1U] */
    | (0U << 8U) /* ENA */
    | (0U << 9U) /* CLK */
    | (0U << 10U) /* SIMO */
    | (0U << 11U); /* SOMI */

    /** - SPI2 Port pullup / pulldown selection */
    spiREG2->PC8 = 1U /* SCS[0] */
    | (1U << 1U) /* SCS[1] */
    | (1U << 8U) /* ENA */
    | (1U << 9U) /* CLK */
    | (1U << 10U) /* SIMO */
    | (1U << 11U); /* SOMI */

    /** - SPI2 Port pullup / pulldown enable*/
    spiREG2->PC7 = 0U /* SCS[0] */
    | (0U << 1U) /* SCS[1] */
    | (0U << 8U) /* ENA */
    | (0U << 9U) /* CLK */
    | (0U << 10U) /* SIMO */
    | (0U << 11U); /* SOMI */

    /* SPI2 set all pins to functional */
    spiREG2->PC0 = 0U /* SCS[0] */
    | (1U << 1U) /* SCS[1] */
    | (0U << 8U) /* ENA */
    | (1U << 9U) /* CLK */
    | (1U << 10U) /* SIMO */
    | (1U << 11U); /* SOMI */

    /** - Initialize TX and RX data buffer Status */
    g_spiPacket_t[1U].tx_data_status = SPI_READY;
    g_spiPacket_t[1U].rx_data_status = SPI_READY;

    /** - Finally start SPI2 */
    spiREG2->GCR1 = (spiREG2->GCR1 & 0xFEFFFFFFU) | (1U << 24U);


    /* USER CODE BEGIN (3) */
    taskEXIT_CRITICAL();
    /* USER CODE END */
    }

  • Bobby,

    I did not see anything wrong in this code.

    I also use spi2 on my board.

    If you simply your code and send to me(haixiao.weng@ti.com), I can debug it on my board.

    Regards,

    Haixiao

  • Bobby,

    Your code works on my bench.

    The only thing might be relavant is: I uncommented the following code in ecmpInit() to make the TPS start correctly.

    while (ecmpIfGetRegister(ECMP_SAFETY_STATUS5) != 7); // BG - THIS BLOCKS US WHEN WE DON'T POWER UP INTO DIAGNOSTIC...

    Regards,

    Haixiao

  • Haixiao,

    I did uncomment that line and it still did not work.

    The reason that line is there is that after the TPS enters the ACTIVE state, it stays there until a hard power reset. So restarting in the debugger or via soft power reset, execution blocks forever on that line, which is why I have it commented. Is it a requirement that the TPS be in a DIAGNOSTIC state in order to use DIAG_OUT?  I have configured the ECMP_SAFETY_CHECK_CONTROL register both ways - to stay in DIAGNOSTIC and to allow a transition to ACTIVE and I have not gotten it to work either way.

    Do you have an answer to my earlier question repeated below?

    I believe we the TPS chips we are using are from a pre-finalized release of the device – do you know if there was ever a hardware issue around this functionality?

    Thanks,

    Bobby

  • Bobby,

    In my code, it is used in Diagnostic mode. I will try the active mode and let you know the result.

    My TPS chips were in earlier stage too, the board was assambled back into June 2012. I don't know if any functional problem in TPS chip prior to that. Can you read out the device ID and version? I can check with the TPS team.

    Thanks,

    Haixiao

  • I tested the diagnostic pin in active mode, it is working as well.

    Regards,

    Haixiao

  • Can you provide a link to schematic of Eval board you are using, we would like to compare connectivity?

  • Thank you for prompt reply. This is very similar to what we have on our board, we just use 10V as VBATP and VBAT_SAFING and IGN is directly connected to VBATP, not pulled to 5V.

    DIAG_OUT was measured with pin lifted and with strong pull-up to 3.3V - still showed only  20mV reading, so appears to be driven low by TPS65381.

    Regards,

    Predrag

  • I run out of ideas. Is it possible that you guys ship one board to us, then I can debug on your board?

    Regards,

    Haixiao

  • Haixiao,

    The chip is marked with the following: 37CJ6QT / TPS5381.

    From DEV_ID, ID = 1.  From DEV_REV, Revision = 48d

    Also, VMonStatus1 and VMonStatus2 = 0.  DevCfg1 = 128d, DevCfg2 = 192d.

    Thanks,

    Bobby

  • Can you run these two functions and let me know the result? it is included in your functions.

    unsigned short ecmpGetDeviceRevision(void)
    {
     return ecmpIfGetRegister(ECMP_DEVICE_REVISION);
    }


    /** @fn unsigned short ecmpGetDeviceId(void)
    *   @brief Read device identifier
    *
    *   Reads the device identifier.
    */
    unsigned short ecmpGetDeviceId(void)
    {
     return ecmpIfGetRegister(ECMP_DEVICE_ID);
    }

    Thanks,

    Haixiao

     

  • Hi Haixiao - those were included in my last post; revision 48, id:1.

    Bobby

  • My device ID=1, REV is 0x11.

    Another device ID=1, REV is 0x20.

    Both are working

    The TPS65381 that you are using is newer than mine. I don't know why it is not working in your bench.

    Thanks,

    Haixiao

  • On power up, DIAG_OUT is initially in high impedance state, but is sharply pulled low ~40ms after power-up (cold start), and ~2-3ms after receiving init commands from Hercules.

    When Hercules is restarted, by appying reset to pin nPORRST (warm start, hard reset) , DIAG_OUT pin starts to operate correctly, changing analog value every 100ms.

    Please advise.

  • Bobby,

    What if you comment "portBaseType xStatus = xTaskCreate(&xprvTPS65381_Monitor_Task_Param, NULL);"? Will the waveform be the same? I want to narrow down the problem.

    Thanks,

    Haixiao

  • Haixiao,

    Without the monitoring task, the output of DIAG_OUT (without a pull-up) gradually tapers off, as opposed to being driven low sharply.  This is also the behavior we see on the pin when powering up with no code running on the Hercules at all.  This clearly narrows the problem down to the monitoring code.

    Bobby

  • Haixiao,

    I am replacing an earlier post that identified a software issue that turned out to be a hardware problem.

    Everything works fine now.  Thanks for all of your help.

    Bobby

  • Bobby,

    Good to hear that. There are sth in my mind:

    In your code, there are two different tasks, one initialize the TPS and serve watchdog, another one check the integrity of the TPS. I don't know their prioties since I don't have all the code. Suppose the low priority task issue a SPI command (wait for the transfer finish flag), the high priority task break in and issue another SPI command, sth weired might occur. I am thinking adding some code to the ecmp_if.c to disable the interrupt and re-enable it after the SPI command finished. like:

    asm(" cpsid i"); /*disable the interrupt*/

    /*interface with the TPS65381*/

    .........

    asm(" cpsie i"); /*enable the interrupt*/

    Thanks,

    Haixiao

  • Haixiao,

    In fact, we have 2 tasks as you describe and the watchdog task is running at a higher priority than the TPS monitoring task.  I suspect that we may be running into issues as a result of these 2 tasks fighting over the SPI bus and have seen some lockups since implementing the monitoring task.  Just so I understand the scope of what you are suggesting, within the methods in ecmp_if.c (SetBit, SetRegister, GetBit, GetRegister, SetMaskedRegister), you would protect the sections of code that do spi access (both read and write) with the disable/enable interrupt calls?  I would like to limit the "disable interrupts" window as much as possible - do you see negative impact (other than a slight performance hit) to disabling interrupts for the entire scope of each of these methods or would you suggest limiting their scope to just the spi register access?  Could you provide an example of what you are suggesting?

    (I have modified our ecmp_if.c to enable/disable interrupt for the entire body of each of these methods and am currently testing this - I will let you know if we still have issues.)

    Thanks,

    Bobby

  • Bobby,

    This is exactly what I mean. If you don't like to disable the interrupt for so long, how about use Mutexes/Binary Semapore to guard the SPI call? This could introduce priority inversion. Like:

    void ecmpIfSetRegister(unsigned short reg, unsigned short value)
    {
     volatile unsigned short dummy;
        unsigned short command = ecmpIfCOMMAND[reg].Write | value;
        const unsigned int max_wait = 100000000; // works out to ~5s
        int i;

    xSemaphoreTake(....) or,

    asm(" cpsid i"); /*disable the interrupt*/
        spiREG2->DAT1 =  0x04FE0000 | command;
        i = 0;
        while (((spiREG2->FLG & 0x100)!=0x100) && (i++ < max_wait)) ;
        dummy = (spiREG2->BUF) & 0xFF;

    xSemaphoreGive(....) or,

    asm(" cpsie i"); /*enable the interrupt*/


  • Please find the updated version of safety diagnostic library(for Hercules MCU) with support for the TPS Driver.
    http://www.ti.com/tool/safeti_diag_lib
    The Product information page is not up to date and will be updated soon.

    Please do provide feedback if any on the same.