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.

TMS570LS0432: HalCoGen SPI, RXINTFLG never sets

Part Number: TMS570LS0432
Other Parts Discussed in Thread: HALCOGEN,

Hi everybody,

I am using a Hercules TMS570LS0432 Launchpad and am using HalCoGen drivers with a lot of success. However the SPI driver has been giving me trouble. 

When calling spiTransmitData() or spiTransmitAndReceiveData() functions it will sometimes (but not all the time) get stuck when waiting for the RXINTFLG bit to set, i.e. "while((spi->FLG & 0x00000100U) != 0x00000100U)". Through the debugger I can see that the SPI Flag register is set to 0x01000200 (TXINTFLG is set).

I have a 4-channel scope connected and can see that the chip select and clock lines are pulled high after clocking 8 bits, so transmission seems to have occurred okay. What am I doing wrong, and what can I do to fix this? 

Following are some code snippets, I hope it's enough to help me with this.

My function call:

spiTransmitData(spiREG2, &spiFmt0, 1, txBuf);

My spiDAT1_t struct passed into the functions in question:

spiDAT1_t spiFmt0 = {
.CS_HOLD = 1,
.WDEL = 1,
.DFSEL = SPI_FMT_0,
.CSNR = 0x00
};

In HalCoGen's spiInit(void):

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

Thank you for any insight into this problem,
Matthew

  • Hello Matthew,

    As I would suspect, the polling in the functions spiTransmitData and spiTransmitAndReceive are only looking at the RXINTFLG since for every transmit there is a receive when using the SPI in a full duplex mode of operation. So, when the SPI Flag register has the value 0x01000200, meaning the TXINTFLG is set, it stays in the polling loop.

    What isn't clear in your post is if you are intending to use the SPI in full duplex or half duplex. i.e., is there data also shifted into the device when data is shifted out? I assume this to be the case or, at least the intended case given your post title. However, you not that you have looked at Tx and SPICLK, and CS pins on the scope bu don't explicitly state the condition of the RX line. ALso to be on the same page, I assume you are using a standard SPI or the mibSPI in compatibility mode and that the LS0432 is the master? Are these assumptions correct?

    If you see that the Rx (SOMI) signal is good and reflects the intended/expected data, what is the content of the Rx Buffer when the Tx flag is set? Is the data in the Rx buffer correct and reflect the same as the scope plot?
  • Hi Chuck!

    You're assumptions are correct; sorry about that, I should have given more details in my post. Full duplex; LS0432 is the master.

    My slave (an LTC6811-1 battery stack monitor) reads in a 4-byte command and responds with a certain amount of data. The LTC6811 expects the CS pin to be pulled low for the entire transaction, and the only way I found to do that is by using the spiTransmitAndReceive() function with CSHOLD=1 and passing in the total number of bytes, i.e. 4-byte command + X-byte data from slave. However, the LTC6811 slave doesn't actually assert anything on the SOMI line while I am sending the first 4-bytes. Maybe this is part of the problem? I assumed it would just be read as all 1's (as the SOMI line is pulled up) and I could just toss out the data.

    Additionally, the LTC6811 slave needs to be woken up before SPI transactions can take place. An applications engineer at LTC has told me that I can do this by clocking 8-bits of 0's or 1's on the SIMO line (with a full high-to-low-to-high cycle of the CS pin) before sending an actual command. I do this with spiTransmitData(spiREG2, &spiFmt0, 1, &onesBuf). Sometimes the RXINTFLG traps here, and sometimes it succeeds and gets trapped in the next call, which is spiTransmitAndReceiveData(spiREG2, &spiFmt0, 12, txData, rxData).

    In direct response to your last question, there is a match between the RX Buffer register and what I see on the scope. The RXINTFLG infinite loop always seems to occur either after "waking up" the slave with 8-bits of 1's, or after the first byte of the command. Because of this, the SOMI line is never asserted (the slave is never outputting data) so the line is held high. The SPI RX buffer registers therefore reads as 0xFF, which is what I would expect.

    Hope this communicates my situation a little better, and thanks for your help,

    Matthew
  • Hello Matthew,

    Speaking with a colleague and reading a bit more of the TRM, there are couple of things to consider. First, what is the state of the nENA pin? have you configured it as GIO if you are not using it? Otherwise it should be tied inactive. If left floating it could result in intermittent behavior as you described because it would cause the Tx to be held off. Also, in regard to the TxINTFlg, this flag indicates only that the Tx buffer is empty. In the case where the nENA is potentially floating, it would mean that the Tx data has been shifted out of the Tx Buffer into the shift register but not actually put onto the bus.

    Can you have a look at the nENA configuration and make sure its not floating by initializing it into a non-functional mode?

    If this is already the case for your application (nENA is handled), I would need to take a deeper look at the behavior.
  • Hi Chuck,

    The SPI2 ENA pin was set to be a GPIO. Just to try something, I have set the pin as an output with both high and low logic levels; neither changed the behavior I am experiencing.

    I am having a hard time understanding why the TXINTFLG would set, but not the RXINTFLG. I only know as much as what's in the TRM, but it seems like the SPI peripheral should be happy to clock in whatever values are on the SOMI pin regardless of their state. Unless, of course, the SPI hardware is expecting current flow like a push/pull setup.

    Here are some more complete code snippets that may help. It includes a whittled-down version of my main loop, as well as the HalCoGen-generated spiInit() and spiTransmitAndReceive() functions. The only changes I've made to them (if I remember correctly) are in spiInit() and change the setup of the nENA pin. 

    Sometimes the code will reach the while() loop and run the last spiTransmitAndReceiveData() function a couple of times before stopping b/c of the RXINTFLG. Other times, it sill stop at the first spiTransmitData() call.

    Meanwhile, I have written my own SPI function that ignores the RXINTFLG bit and am successfully communicating with my slave device. This may be dangerous practice, so I would like to use the HalCoGen drivers if possible. 

    Thanks again,

    Matthew

    #include "sys_common.h"
    #include "spi.h"
    
    
    void main(void)
    {
    	uint16_t zeroBuf = 0xFF;
    	uint16_t spiTxData[12] = {0, 2, 0x2b, 0x0a, 0,0,0,0,0,0,0,0};
    	uint16_t spiRxData[12];
    
    	spiInit();
    
    	//wake up the slave
    	spiTransmitData(spiREG2, &spiFmt0, 1, &zeroBuf);
    
    	//send first command
    	spiTransmitAndReceiveData(spiREG2, &spiFmt0, 12, spiTxData, spiRxData);
    
    	while (1)
    	{
    		for(i=0; i<10000; i++);
    		spiTransmitAndReceiveData(spiREG2, &spiFmt0, 12, spiTxData, spiRxData);
    	}
    }
    
    void spiInit(void)
    {
    /* USER CODE BEGIN (2) */
    /* USER CODE END */
    
        /** @b initialize @b SPI2 */
    
        /** bring SPI out of reset */
        spiREG2->GCR0 = 0U;
        spiREG2->GCR0 = 1U;
    
        /** SPI2 master mode and clock configuration */
        spiREG2->GCR1 = (spiREG2->GCR1 & 0xFFFFFFFCU) | ((uint32)((uint32)1U << 1U)  /* CLOKMOD */
                      | 1U);  /* MASTER */
    
        /** SPI2 enable pin configuration */
        spiREG2->INT0 = (spiREG2->INT0 & 0xFEFFFFFFU)| (uint32)((uint32)0U << 24U);  /* ENABLE HIGHZ */
    
        /** - Delays */
        spiREG2->DELAY = (uint32)((uint32)200U << 24U)  /* C2TDELAY */
                       | (uint32)((uint32)2U << 16U)  /* T2CDELAY */
                       | (uint32)((uint32)0U << 8U)   /* T2EDELAY */
                       | (uint32)((uint32)0U << 0U);  /* C2EDELAY */
    
        /** - Data Format 0 */
        spiREG2->FMT0 = (uint32)((uint32)2U << 24U)  /* wdelay */
                      | (uint32)((uint32)0U << 23U)  /* parity Polarity */
                      | (uint32)((uint32)0U << 22U)  /* parity enable */
                      | (uint32)((uint32)0U << 21U)  /* wait on enable */
                      | (uint32)((uint32)0U << 20U)  /* shift direction */
                      | (uint32)((uint32)1U << 17U)  /* clock polarity */
                      | (uint32)((uint32)0U << 16U)  /* clock phase */
                      | (uint32)((uint32)159U << 8U) /* baudrate prescale */
                      | (uint32)((uint32)8U << 0U);  /* data word length */
        /** - Data Format 1 */
        spiREG2->FMT1 = (uint32)((uint32)2U << 24U)  /* wdelay */
                      | (uint32)((uint32)0U << 23U)  /* parity Polarity */
                      | (uint32)((uint32)0U << 22U)  /* parity enable */
                      | (uint32)((uint32)0U << 21U)  /* wait on enable */
                      | (uint32)((uint32)0U << 20U)  /* shift direction */
                      | (uint32)((uint32)1U << 17U)  /* clock polarity */
                      | (uint32)((uint32)0U << 16U)  /* clock phase */
                      | (uint32)((uint32)79U << 8U) /* baudrate prescale */
                      | (uint32)((uint32)8U << 0U);  /* data word length */
    
        /** - Data Format 2 */
        spiREG2->FMT2 = (uint32)((uint32)2U << 24U)  /* wdelay */
                      | (uint32)((uint32)0U << 23U)  /* parity Polarity */
                      | (uint32)((uint32)0U << 22U)  /* parity enable */
                      | (uint32)((uint32)0U << 21U)  /* wait on enable */
                      | (uint32)((uint32)0U << 20U)  /* shift direction */
                      | (uint32)((uint32)1U << 17U)  /* clock polarity */
                      | (uint32)((uint32)0U << 16U)  /* clock phase */
                      | (uint32)((uint32)79U << 8U) /* baudrate prescale */
                      | (uint32)((uint32)8U << 0U);  /* data word length */
    
        /** - Data Format 3 */
        spiREG2->FMT3 = (uint32)((uint32)0U << 24U)  /* wdelay */
                      | (uint32)((uint32)0U << 23U)  /* parity Polarity */
                      | (uint32)((uint32)0U << 22U)  /* parity enable */
                      | (uint32)((uint32)0U << 21U)  /* wait on enable */
                      | (uint32)((uint32)0U << 20U)  /* shift direction */
                      | (uint32)((uint32)1U << 17U)  /* clock polarity */
                      | (uint32)((uint32)0U << 16U)  /* clock phase */
                      | (uint32)((uint32)79U << 8U) /* baudrate prescale */
                      | (uint32)((uint32)8U << 0U);  /* data word length */
    
        /** - set interrupt levels */
        spiREG2->LVL = (uint32)((uint32)1U << 9U)  /* TXINT */
                     | (uint32)((uint32)1U << 8U)  /* RXINT */
                     | (uint32)((uint32)1U << 6U)  /* OVRNINT */
                     | (uint32)((uint32)1U << 4U)  /* BITERR */
                     | (uint32)((uint32)1U << 3U)  /* DESYNC */
                     | (uint32)((uint32)1U << 2U)  /* PARERR */
                     | (uint32)((uint32)1U << 1U) /* TIMEOUT */
                     | (uint32)((uint32)1U << 0U);  /* DLENERR */
    
        /** - clear any pending interrupts */
        spiREG2->FLG |= 0xFFFFU;
    
        /** - enable interrupts */
        spiREG2->INT0 = (spiREG2->INT0 & 0xFFFF0000U)
                      | (uint32)((uint32)0U << 9U)  /* TXINT */
                      | (uint32)((uint32)1U << 8U)  /* RXINT */
                      | (uint32)((uint32)0U << 6U)  /* OVRNINT */
                      | (uint32)((uint32)0U << 4U)  /* BITERR */
                      | (uint32)((uint32)0U << 3U)  /* DESYNC */
                      | (uint32)((uint32)0U << 2U)  /* PARERR */
                      | (uint32)((uint32)0U << 1U) /* TIMEOUT */
                      | (uint32)((uint32)0U << 0U);  /* DLENERR */
    
        /** @b initialize @b SPI2 @b Port */
    
        /** - SPI2 Port output values */
        spiREG2->PC3 =    (uint32)((uint32)1U << 0U)  /* SCS[0] */
                        | (uint32)((uint32)1U << 1U)  /* SCS[1] */
                        | (uint32)((uint32)1U << 2U)  /* SCS[2] */
                        | (uint32)((uint32)1U << 3U)  /* SCS[3] */
                        | (uint32)((uint32)1U << 9U)  /* CLK */
                        | (uint32)((uint32)0U << 10U)  /* SIMO */
                        | (uint32)((uint32)0U << 11U) /* SOMI */
                        | (uint32)((uint32)0U << 8U); /* ENA */
    
        /** - SPI2 Port direction */
        spiREG2->PC1  =   (uint32)((uint32)1U << 0U)  /* SCS[0] */
                        | (uint32)((uint32)1U << 1U)  /* SCS[1] */
                        | (uint32)((uint32)1U << 2U)  /* SCS[2] */
                        | (uint32)((uint32)1U << 3U)  /* SCS[3] */
                        | (uint32)((uint32)1U << 9U)  /* CLK */
                        | (uint32)((uint32)1U << 10U)  /* SIMO */
                        | (uint32)((uint32)0U << 11U) /* SOMI */
                        | (uint32)((uint32)1U << 8U); /* ENA */
    
        /** - SPI2 Port open drain enable */
        spiREG2->PC6  =   (uint32)((uint32)0U << 0U)  /* SCS[0] */
                        | (uint32)((uint32)0U << 1U)  /* SCS[1] */
                        | (uint32)((uint32)0U << 2U)  /* SCS[2] */
                        | (uint32)((uint32)0U << 3U)  /* SCS[3] */
                        | (uint32)((uint32)0U << 9U)  /* CLK */
                        | (uint32)((uint32)0U << 10U)  /* SIMO */
                        | (uint32)((uint32)0U << 11U); /* SOMI */
    
        /** - SPI2 Port pullup / pulldown selection */
        spiREG2->PC8  =   (uint32)((uint32)1U << 0U)  /* SCS[0] */
                        | (uint32)((uint32)1U << 1U)  /* SCS[1] */
                        | (uint32)((uint32)1U << 2U)  /* SCS[2] */
                        | (uint32)((uint32)1U << 3U)  /* SCS[3] */
                        | (uint32)((uint32)1U << 9U)  /* CLK */
                        | (uint32)((uint32)1U << 10U)  /* SIMO */
                        | (uint32)((uint32)1U << 11U); /* SOMI */
    
        /** - SPI2 Port pullup / pulldown enable*/
        spiREG2->PC7  =   (uint32)((uint32)0U << 0U)  /* SCS[0] */
                        | (uint32)((uint32)0U << 1U)  /* SCS[1] */
                        | (uint32)((uint32)0U << 2U)  /* SCS[2] */
                        | (uint32)((uint32)0U << 3U)  /* SCS[3] */
                        | (uint32)((uint32)0U << 9U)  /* CLK */
                        | (uint32)((uint32)0U << 10U)  /* SIMO */
                        | (uint32)((uint32)0U << 11U); /* SOMI */
    
        /* SPI2 set all pins to functional */
        spiREG2->PC0  =   (uint32)((uint32)1U << 0U)  /* SCS[0] */
                        | (uint32)((uint32)1U << 1U)  /* SCS[1] */
                        | (uint32)((uint32)1U << 2U)  /* SCS[2] */
                        | (uint32)((uint32)1U << 3U)  /* SCS[3] */
                        | (uint32)((uint32)1U << 9U)  /* CLK */
                        | (uint32)((uint32)1U << 10U)  /* SIMO */
                        | (uint32)((uint32)1U << 11U); /* SOMI */
    
    
        spiREG2->PC5 = (uint32)((uint32)1U << 8U);  /* ENA */
    
        /** - 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) | 0x01000000U;
    
    /* USER CODE BEGIN (3) */
    /* USER CODE END */
    }
    
    
    uint32 spiTransmitAndReceiveData(spiBASE_t *spi, spiDAT1_t *dataconfig_t, uint32 blocksize, uint16 * srcbuff, uint16 * destbuff)
    {
        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;
    
    /* USER CODE BEGIN (14) */
    /* USER CODE END */
        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)
            {
            } /* Wait */
            /*SAFETYMCUSW 45 D MR:21.1 <APPROVED> "Valid non NULL input parameters are only allowed in this driver" */
            *destbuff = (uint16)spi->BUF;
            /*SAFETYMCUSW 567 S MR:17.1,17.4 <APPROVED> "Pointer increment needed" */
            destbuff++;
    
            blocksize--;
        }

  • Matthew,

    I don't have a definitive answer for you yet, but I do have a couple of observations based on your code and my understanding of some of the format options.

    First, as noted in your original post, CSHOLD = 1. When CSHOLD = 1, C2TDELAY and T2CDELAY settings are ignored so setting them as you do in the above initialization code won't cause and specific behavior related to these delay values. On the other hand, the WDELAY parameter is still honored even with CSHOLD=1. This means that the cS will be de-asserted for (WDELAY+2) X VCLK period between packets. I had thought that you stated that your slave device required the CS to remain asserted between transmissions?

    Finally, for test purposes, have you considered enabling loopback such that you receive what you send to see if this is some issue with the external device or some odd behavior stricly related to the LS0432? The device has a digital loopback and an analog loop back mode that can be used. The digital Loopback is all internal logic where the analog actually crosses through the analog input and output buffers of the pin.