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.

TMS320F28P659DK-Q1: TMS320F28P659DK: LIN Header Only

Part Number: TMS320F28P659DK-Q1
Other Parts Discussed in Thread: C2000WARE

I am attempting to use the TMS320F28P659DK LIN peripheral and have been running into some issues. I am able to run the C2000Ware example lin_ex1_loopback_interrupts and it appears to run fine as I see Rx data equal to Tx data and the interupt counter went up as expected. I then took that example and commented out the LIN_enableIntLoopback line so I can watch the Tx pin externally with an oscope. I am able to see the header of the LIN packet, but there is no data. It also seems to be stuck waiting for the Tx buffer to empty, which seems to be a symptom of the issue. As far as I read, LIN_setIDByte is supposed to send out the header and data, but that does not appear to be happening. Can anyone provide insight on what be going on here? I am using CCS 12.8.1 with C2000Ware 6.0.0.0.

  • Here is the modified example code. I commented out all the interrupt configs, read checks and put the transmit sequence in an infinite for loop. With the line while(!LIN_isTxBufferEmpty(LINA_BASE)); uncommented, I only get just a header one time and the software sits in that while loop because the Tx buffer is not getting emptied. With that line commented out, I get repeats of just the header. Comments in the example code state that LIN_sendData writes to the Tx buffers, but does not initiate a transmission and then LINsetIDByte initiates a header followed by data transmission. In the TRM, it states that writing IDBYTE in the LINID register initiates a header transmission and writing to TD0 in the LINTD0 register initiates a transmission. Seems a little conflicting.

    There is also something going on while looking at the LinaRegs registers through the debugger. It looks like all of the 32-bit LIN registers mirror the upper and lower 16-bits. For instance, the LINTD0 register in software is being set to 0x11345678, but the value in the register viewer is 0x56785678 and I am unable to manually change it to make the upper and lower 16-bits not be the same. Seems like this should be a debugger side issue, though I'm using the gel file from the latest version of CCS. This is preventing me from manually adjusting registers to try and get it to transmit data with the header.

    //
    // Included Files
    //
    #include "driverlib.h"
    #include "device.h"
    
    //
    // Defines
    //
    #define FRAME_LENGTH    0x8
    #define LIN_PASS        0xABCD
    #define LIN_FAIL        0xFFFF
    
    //
    // Globals
    //
    volatile uint32_t level0Count = 0;
    volatile uint32_t level1Count = 0;
    volatile uint32_t vectorOffset = 0;
    uint16_t result;
    uint16_t txData[8] = {0x11, 0x34, 0x56, 0x78, 0x9A, 0xAB, 0xCD, 0xEF};
    uint16_t rxData[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
    
    //
    // Function Prototypes
    //
    __interrupt void level0ISR(void);
    __interrupt void level1ISR(void);
    
    //
    // Main
    //
    void main(void)
    {
        uint32_t i, dataIndex;
        uint16_t txID, error;
    
        //
        // Initialize device clock and peripherals
        //
        Device_init();
    
        //
        // Initialize GPIO and configure GPIO pins for LINTX/LINRX
        //
        Device_initGPIO();
        GPIO_setPinConfig(DEVICE_GPIO_CFG_LINTXA);
        GPIO_setPinConfig(DEVICE_GPIO_CFG_LINRXA);
    
        //
        // Initialize PIE and clear PIE registers. Disables CPU interrupts.
        //
        Interrupt_initModule();
    
        //
        // Initialize the PIE vector table with pointers to the shell Interrupt
        // Service Routines (ISR).
        //
        Interrupt_initVectorTable();
        EINT;
        ERTM;
    
        //
        // Interrupts that are used in this example are re-mapped to
        // ISR functions found within this file.
        // This registers the interrupt handler in PIE vector table.
        //
        //Interrupt_register(INT_LINA_0, &level0ISR);
        //Interrupt_register(INT_LINA_1, &level1ISR);
    
        //
        // Enable the LIN interrupt signals
        //
        //Interrupt_enable(INT_LINA_0);
        //Interrupt_enable(INT_LINA_1);
    
        //
        // Initialize the LIN module
        //
        LIN_initModule(LINA_BASE);
    
        //
        // Enable Internal Loopback mode
        //
        //LIN_enableIntLoopback(LINA_BASE);
    
        //
        // Enable interrupts for when an header identifier is received
        //
        //LIN_enableInterrupt(LINA_BASE, LIN_INT_ID);
    
        //
        // Set the interrupt priority line
        // Default is set to Interrupt line 0 (high priority)
        // Comment out "LIN_setInterruptLevel0" and uncomment
        // "LIN_setInterruptLevel1" to change to interrupt line 1 (low priority)
        //
        //LIN_setInterruptLevel0(LINA_BASE, LIN_INT_ALL);
        //LIN_setInterruptLevel1(LINA_BASE, LIN_INT_ALL);
    
        //
        // Enable parity check
        //
        LIN_enableParity(LINA_BASE);
    
        //
        // Enable global interrupt lines and clear status to known value
        //
        //LIN_enableGlobalInterrupt(LINA_BASE, LIN_INTERRUPT_LINE0);
        //LIN_enableGlobalInterrupt(LINA_BASE, LIN_INTERRUPT_LINE1);
        //LIN_clearGlobalInterruptStatus(LINA_BASE, LIN_INTERRUPT_LINE0);
        //LIN_clearGlobalInterruptStatus(LINA_BASE, LIN_INTERRUPT_LINE1);
    
        //
        // Perform 8 data transmissions with different transmit IDs and varying
        // number of bytes transmitted. Received data is checked for correctness.
        //
        for(;;)
        //for(i = 1 ; i <= FRAME_LENGTH; i++)
        {
            vectorOffset = 0;
    
            //
            // Create a new transmit ID and update with parity bits
            //
            txID = (0x10 + i);
            txID = LIN_generateParityID(txID);
    
            //
            // Increment the value of the first 8-bits of the transmitted
            // message data
            //
            //txData[0]++;
    
            //
            // Reset values in receive buffer array
            //
            for(dataIndex=0; dataIndex < 8; dataIndex++)
            {
                rxData[dataIndex] = 0xFF;
            }
    
            //
            // Set the frame length (number of bytes to be transmitted)
            //
            LIN_setFrameLength(LINA_BASE, 8);
    
            //
            // This places data into the transmit buffer.
            // No ID or data is placed on the bus and transmitted yet.
            //
            LIN_sendData(LINA_BASE, txData);
    
            //
            // Set the message ID to initiate a header transmission.
            // This causes the ID to be written to the bus followed by the
            // data in the transmit buffers.
            //
            LIN_setIDByte(LINA_BASE, txID);
    
            //
            // Wait for ISR to trigger and run upon reception of the ID header
            //
            //while(vectorOffset != LIN_VECT_ID);
    
            //
            // Wait until Transmit buffer is empty and has completed transmission
            //
            //while(!LIN_isTxBufferEmpty(LINA_BASE));
    
            //
            // Read the received data in the receive buffers
            //
            LIN_getData(LINA_BASE, rxData);
    
            //
            // Verify the transmitted data matches the received data
            //
            /*
            for (dataIndex=0; dataIndex < i; dataIndex++)
            {
                if (rxData[dataIndex] != txData[dataIndex])
                {
                    error++;
                }
            }
            */
        }
    
        //
        // Check if any data errors occurred
        //
        if(error == 0)
        {
            result = LIN_PASS;
        }
        else
        {
          result = LIN_FAIL;
        }
    
        //
        // Example completed. Check "result" variable for completion status.
        //
        asm("   ESTOP0");
    }

  • Hi Matt,

    Please see the below thread about an extra field that needs to be configured to do external loopback between two instances on the same C2000.

    (+) LAUNCHXL-F280039C: lin_ex7_external_loopback - C2000 microcontrollers forum - C2000Tm︎ microcontrollers - TI E2E support forums

    Best Regards,

    Delaney

  • Thanks Delaney. It appears to be working as expected now. I am a bit confused as I am not using both LIN peripherals to run a loopback test. I am only using LINA as a commander and watching the tx pin with an oscope. Can you explain why enabling external loopback makes the single LIN peripheral transmit header + data and having the external loopback disabled makes the single LIN peripheral only transmit the header?

  • Hi Matt,

    I see, I misunderstood your original message, my apologies. By nature, LIN requires a responder to be connected on the bus in order to send data frames out. Seeing just the header is expected in this case. Can you try connecting a responder to the bus from a different device and scoping the signals? You should see the data in this case (or if the external loopback is used and setup as described in the other thread).

    It looks like all of the 32-bit LIN registers mirror the upper and lower 16-bits. For instance, the LINTD0 register in software is being set to 0x11345678, but the value in the register viewer is 0x56785678 and I am unable to manually change it to make the upper and lower 16-bits not be the same.

    This is due to the fact that LIN is a byte peripheral, see documentation here. CCS displays the same data twice in this case since the C28x CPU is 16-bit addressable. 

    Best Regards,

    Delaney

  • Delaney,

    I can't find any information online or understand why a LIN master would require any other device to be on the same physical bus in order for the master to be able to send out data after the header. Maybe instead the LIN peripheral requires a transceiver to be connected to it to be able to send data, which is possibly functionally equivalent to have external loopback enabled? On a LAUNCHXL-28P65X, there is no LIN transceiver and data cannot be sent out by the master unless external loopback is enabled. On our development hardware, there IS a LIN transceiver and the master is able to send out header + data without external loopback being enabled.

    As far as the register view goes, is that a known short coming of CCS? For instance, SCIGCR1 shows 0x1CE41CE4 (upper and lower 16-bits mirrored) in the register viewer, but when I use HWREG_BP to read it, I get 0x03021CE4, which is what I expect to see. This discrepancy seems to be present for all of the 32-bit LIN registers.  

  • Hi Matt,

    Let me consult one of the other experts and get back to you.

    Best Regards,

    Delaney

  • Hi Matt,

    Apologies for the delay. You were right, my earlier statement was incorrect. I believe your issue is actually that the TX and RX lines are not looped back, and hence only the header will be sent by the commander device. The transceiver should do this loopback internally, which is why you don't see the issue there.

    By nature, LIN requires the transmit line to be looped back to the receive line in order to send data frames out (as well as being connected to the receiving device). A LIN commander will only send data frames if it sees a header on the bus telling it to - it needs to receive its own header back on the RX pin in order to send out data. 

    It's not necessarily a shortcoming of CCS itself - but a discrepancy between the architecture of the C2000 device vs. the LIN peripheral. When debugging a device with a 16-bit processor in CCS, like the C28x, the memory browser will display each value assuming 16-bit words. CCS is not able to alter the way it displays the memory depending on the specific peripheral registers being displayed, it assumes a 16-bit system for all of the memory. For byte peripherals like LIN:  "Even and odd addresses to 16-bit data both map to the same data element on the byte peripheral." The device itself technically maps the same physical entity in LIN to two different C28x addresses, so CCS shows the data at both of these addresses, which is the same.

    The HWREG_BP takes care of this difference using the compiler. I'm not sure exactly how the compiler does this, but it likely throws out the mirrored values somehow.

    Best Regards,

    Delaney

  • Thanks for following up on that.