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.

TMS320F280049C: LIN module in slave mode - how to initiate response transmission

Part Number: TMS320F280049C
Other Parts Discussed in Thread: C2000WARE, LAUNCHXL-F280049C

Hello,

In the technical reference manual for the F280049C (SPRUI33D), there is insufficient information about response transmission in slave mode
and the examples that come with C2000ware are all for Master Mode.
I am able to receive frames in slave mode and the masks for Rx and TX seem to be working correctly. Loopback is turned off. I have tried simply
writing the send data to the LINTD0 and LINTD1 registers, but nothing is coming out of the F280049. The LIN master
is sending proper signals:

Do you have an example of response transmission in slave mode or some guidelines on how this is done?

Kind Regards,

John

  • Hi John,

    I apologize for the delay due to the US holiday. I am currently looking into whether there are legacy device examples with more emphasis on the response frame, but in the meantime could you assist with clarifying the system a bit:

    • The device that is transmitting to the C2000 device is not the same C2000 device communicating to itself, correct?
    • Also, what are the voltage input/output capabilities of the transceiver? The transceiver mentioned seems to be 2V capable which would be okay, so I am assuming it is not a typo. Reason for this question is C2000 devices are 3.3V logic levels for LIN output, so if the transceiver is meant for 5V logic levels this will prevent output from the transceiver level.
    • Can you verify if the RX receive frame in the image provided is also before the transceiver (at the C2000-LIN-RX pin)? I am assuming so, but wanted to sanity check.

    Regards,

    Vince

  • Hi John,

    I was able to find an example from an older device that (I believe) is doing what you're looking to do, but on a single C2000 board. You can substitute your transmitting device and just remove the transmitting code from the example.

    The example is located in the following location:

    C2000Ware_VERISION#\device_support\f2803x\examples\c28\lina_external_loopback\Example_2803xLina_EXALB.c

    This example is a bit more low-level, as it uses the bit-field naming directly, but should suffice in showing what is needed to get responses to work in slave mode.

    Essentially, key items are the "IDSLAVETASKBYTE" being set to the proper value, using interrupts for automatic response, and using the "IDBYTE" when transmitting (if doing loopback).

    Regards,

    Vince

  • Hello Vince,

    no Problem. Hope you a a good holiday celebration.

    The answers to your questions:

    1) the transmitting device is a USB to LIN Adapter from Vector and the master is simulated in the CANalyzer software. This is rock solid equipment. Still, I checked the data being sent with in the scope shot and everything is alright: break count, break delimiter, ID, everything is okay.

    2) The transciever is the TLIN-1029 which is powered by the battery, so 12 V.

    3) Sanity check is a good idea. Here is a scope shot of the signals on the TLIN-1029 with LIN (pin 6) on Ch1 and  RxD (Pin 1) on Ch 2. Ch 1 is at 10 V/div and Ch 2 is at 2 V/div. I am seeing 12 V signals on the LIN and 3.3 V Signals on the RxD. Can you confirm?

    For beginners, I've started with the polling mode using the C2000ware example "lin_ex4_loopback_polling". I am aware that it is a load for the processor, but it should be fast enough to work, since nothing else is going on.

    Here is the code I am using:

    while (1)
        {
            msgLoopCount++;
    
            // RxMatch
            receiveCondition = LIN_isRxMatch(LINA_BASE);
            if ( receiveCondition )
            {
                msgRxCount++;
                LIN_clearInterruptStatus(LINA_BASE,LIN_INT_RX);
    
                //
                // Read the received data in the receive buffers
                //
                LIN_getData(LINA_BASE, rxData);
            }
    
            // Tx Match
            sendCondition = LIN_isTxMatch(LINA_BASE);
            if ( sendCondition )
            {
                msgTxCount++;
                LIN_clearInterruptStatus(LINA_BASE,LIN_INT_TX);
    
                //
                // This places data into the transmit buffer.
                // No ID or data is placed on the bus and transmitted yet.
                //
                //LIN_sendData(LINA_BASE, txData);
    
                if (LIN_isTxReady(LINA_BASE) && LIN_isTxBufferEmpty(LINA_BASE))
                {
                    msgTxSend++;
                    //
                    // increase values in send buffer array
                    //
                    for(dataIndex=0; dataIndex < 8; dataIndex++)
                    {
                        if(txData[dataIndex] == 0xFF)
                        {
                            txData[dataIndex] = 0x00;
                        } //if
                        else
                        {
                            txData[dataIndex]++;
                        } //else
                    } // for
                } //if
            } //if
    
            vectorOffset = LIN_getInterruptLine0Offset(LINA_BASE);
            if (vectorOffset == LIN_VECT_ID)
            {
                //
                // clear interrupt
                //
                LIN_clearInterruptStatus(LINA_BASE,LIN_INT_ALL);
            }
    
        }//for / while

    As the TRM suggests, wait first for IDTXFLAG, then check TXRDY and TXEMPTY before writing the 8 bytes to LINTD0 and LINTD1. The counters msgTxCount and msgTxSend are always the same, so all signals are coming in okay, but I never see any signals on TxD (pin 4) of the TLIN-1029.

    As a sanity check, I tested the HW by setting the LINTX as a GPIO and toggeling. The impulse are visible on TxD and on LIN, so the HW is working. Any ideas what is missing in the code?

    Best Regards,

    John

  • Hello Vince,

    I took a look at the example you suggested. Although, the word slave shows up there, as far as I can see, LIN module is set up as a master in loopback mode and I did not see anything which gave me any clues, but maybe I missed something?

    Cheers,

    John

  • Hi John,

    Thanks for the thorough check through, the GPIO toggling is definitely useful since we can rule out any issues between the TX pin and the transceiver.

    Now for the code, could you provide your configuration code for both the LIN and the two RX/TX pins in general? I believe if we're not getting any output (and the txData is being set) then there could be a mismatch on the config.

    If you could also provide the ISRs for the LIN that would be great.

    I'm going to first see if I there's anything that stands out as an issue, and then try to replicate the failure and see where the issue may be.

    Thanks!

    Regards,

    Vince

  • Hello Vince,

    In order to replicate, it is better to have the whole project; attached.

    PCB013_DrvLib_LIN_Int.zip

    The present build is to FLASH and this version is working in polling mode, so no ISRs. Once the basics work, we will move to an interrupt scheme. I am on CCS 11.1.0 and this software is for a custom board with the F280049C in the RSH package.

    LINTXA is on GPIO22 and LINRXA is on GPIO29. The set up is in the main procedure in the file lin_ex4_loopback_polling.c

    Please note that GPIO0 is set to output and must be set to enable the TLIN-1029. Please let me know if you need more information.

    Kind regards,

    John

  • Hi John,

    Quick status update: I am currently still looking into the project files provided, and am trying to first read through the project itself for any inconsistencies before attempting to run it. I expect to have at least an initial idea of where the issue can be by this coming Monday (7/18), possibly sooner. Thanks for your patience in this!

    Regards,

    Vince

  • Hi John,

    As an update, I have spent quite a bit of time trying to figure out what is missing in the code provided, and cannot seem to find the root cause. I am currently working in the opposite direction now to try and debug this: I am starting with a working example and trying to move it closer to your example and finding what breaks it.

    I expect to have some more details soon, but I am reaching out to other team members to see what other settings could block slave response frame.

    Please expect another update by late week.

    Regards,

    Vince

  • Hello Vince,

    Thank you for the update and your support.

    I see what you mean. It is often just finding that one switch and then everything works fine.  I still have not found it.

    What is missing for me is a working example to compare and I don't think that loopback will work for slave mode (or am I wrong here?). Can you provide a working example of slave mode on the LAUNCHXL-F280049C that is not in loopback?

    Working with two boards is also possible.

    The plans for the next revision are in the works and in case there is a hardware issue, this issue needs to be corrected before the plans go into production.

    Best regards,

    John

  • Hi John,

    Here is an example for the LIN slave mode. This walks through the configuration bits needed for LIN slave mode. Some comments may be incorrect, and note that the interrupt functions are not actually used (this is polling). I have not tested this on F28004x, but this should provide all necessary steps to get slave mode operations working.

    //
    // 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};
    uint32_t i, dataIndex, sciflr;
    uint16_t txID, error;
    
    //
    // Function Prototypes
    //
    __interrupt void level0ISR(void);
    __interrupt void level1ISR(void);
    static void MainLoop(void);
    
    //
    // Main
    //
    void main(void)
    {
        //
        // Initialize device clock and peripherals
        //
        Device_init();
    
        //
        // Initialize GPIO and configure GPIO pins for LINTX/LINRX
        //
        Device_initGPIO();
        GPIO_setPinConfig(GPIO_28_LINTXA);
    
        GPIO_setPinConfig(GPIO_29_LINRXA);
    
    
        GPIO_setPinConfig(GPIO_16_XCLKOUT);
        GPIO_setPadConfig(39, GPIO_PIN_TYPE_PULLUP);     // Enable pullup on GPIO39
        GPIO_writePin(39, 1);                            // Load output latch
        GPIO_setPinConfig(GPIO_39_GPIO39);                // GPIO39 = GPIO39
        GPIO_setDirectionMode(39, GPIO_DIR_MODE_OUT);    // GPIO39 = output
    
        //
        // 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;
    
        //
        // Check the arguments.
        //
        ASSERT(LIN_isBaseValid(LINA_BASE));
    
        EALLOW;
    
        //
        // Reset LIN module
        // Release from hard reset
        //
        LIN_disableModule(LINA_BASE);
        LIN_enableModule(LINA_BASE);
    
        //
        // Enter Software Reset State
        //
        LIN_enterSoftwareReset(LINA_BASE);
    
        //
        // Enable LIN Mode
        //
        LIN_disableSCIMode(LINA_BASE);
    
        //
        // Set LIN mode to Master
        //
        LIN_setLINMode(LINA_BASE, LIN_MODE_LIN_SLAVE);
    
        //
        // Enable Fixed baud rate mode
        //
        LIN_disableAutomaticBaudrate(LINA_BASE);
    
        //
        // Use the set frame length and not ID4/ID5 bits for length control
        //
        LIN_setCommMode(LINA_BASE, LIN_COMM_LIN_USELENGTHVAL);
    
        //
        // Setup to continue operating on emulation suspend
        //
        LIN_setDebugSuspendMode(LINA_BASE, LIN_DEBUG_COMPLETE);
    
        //
        // Use Enhanced Checksum
        //
        LIN_setChecksumType(LINA_BASE, LIN_CHECKSUM_ENHANCED);
    
        //
        // Message filtering uses slave task ID byte
        //
        LIN_setMessageFiltering(LINA_BASE, LIN_MSG_FILTER_IDSLAVE);
    
        //
        // Disable Internal loopback for external communication
        //
        LIN_disableIntLoopback(LINA_BASE);
    
        //
        // Enable multi-buffer mode
        //
        LIN_enableMultibufferMode(LINA_BASE);
    
        //
        // Enable parity check on received ID
        //
        LIN_enableParity(LINA_BASE);
    
        //
        // Enable transfer of data to and from the shift registers
        //
        LIN_enableDataTransmitter(LINA_BASE);
        LIN_enableDataReceiver(LINA_BASE);
    
        //
        // Enable the triggering of checksum compare on extended frames
        //
        LIN_triggerChecksumCompare(LINA_BASE);
    
        LIN_sendChecksum(LINA_BASE); // send checksum
        //
        // Set LIN interrupts to disabled
        //
        LIN_disableInterrupt(LINA_BASE, LIN_INT_ALL);
    
        //
        // Set Baud Rate Settings - 100MHz Device
        //
        LIN_setBaudRatePrescaler(LINA_BASE, 599U, 0U);    
        LIN_setMaximumBaudRate(LINA_BASE, 100000000U);
    
        //
        // Set response field to 1 byte
        //
        //LIN_setFrameLength(base, 1U);
        LIN_setFrameLength(LINA_BASE, 8U);
    
        //
        // Configure sync field
        // Sync break (13 + 5 = 18 Tbits)
        // Sync delimiter (1 + 3 = 4 Tbits)
        //
        LIN_setSyncFields(LINA_BASE, 0U, 1U);
    
        //
        // Set Mask ID so TX/RX match will always happen
        //
        LIN_setTxMask(LINA_BASE, 0x83U);
        LIN_setRxMask(LINA_BASE, 0xC3U);
    
        //
        // Disable IODFT testing and external loopback mode
        //
        LIN_disableExtLoopback(LINA_BASE);
    
        //
        // Finally exit SW reset and enter LIN ready state
        //
        LIN_exitSoftwareReset(LINA_BASE);
    
        LIN_setIDSlaveTask(LINA_BASE, 0xE8 );
        EDIS;
    
    
        while(1)
        {
            MainLoop();
        }
    }
    
    #pragma CODE_SECTION(MainLoop, ".TI.ramfunc");
    static void MainLoop(void)
    {
    
    
        // Wait for RX ID or TX ID match
        while(!(LIN_isRxMatch(LINA_BASE) || LIN_isTxMatch(LINA_BASE)));
    
        if (LIN_isRxMatch(LINA_BASE))
        {
            // Wait for RX Ready flag
            while(!LIN_isRxReady(LINA_BASE));
            //
            // Read the received data in the receive buffers
            //
            LIN_getData(LINA_BASE, rxData);
        }
    
        if (LIN_isTxMatch(LINA_BASE))
        {
            //SysCtl_delay(500000);
            // Wait for TX Ready
            while(!LIN_isTxReady(LINA_BASE));
            // Send TX Data
            LIN_sendData(LINA_BASE, txData);
            //
            // Wait until Transmit buffer is empty and has completed transmission
            //
            while(!LIN_isTxBufferEmpty(LINA_BASE));
        }
    
        HWREG(LINA_BASE + LIN_O_SCIFLR) = 0x6000; // clear RXIDFLG and TXIDFLG
    
    }
    
    //
    // LIN High Priority (Level 0) ISR - Interrupt service routine for interrupt
    // line 0. This ISR saves the offset vector indicating the current highest
    // priority pending interrupt.
    //
    __interrupt void
    level0ISR(void)
    {
        //
        // Increment the interrupt count
        //
        level0Count++;
    
        //
        // Read the high priority interrupt vector
        //
        vectorOffset = LIN_getInterruptLine0Offset(LINA_BASE);
        LIN_clearInterruptStatus(LINA_BASE, LIN_INT_ID);
        LIN_clearGlobalInterruptStatus(LINA_BASE, LIN_INTERRUPT_LINE0);
    
        //
        // Acknowledge this interrupt located in group 8
        //
        Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP8);
    }
    
    //
    // LIN Low Priority (Level 1) ISR - Interrupt service routine for interrupt
    // line 1. This ISR saves the offset vector indicating the current highest
    // priority pending interrupt.
    //
    __interrupt void
    level1ISR(void)
    {
        //
        // Increment the interrupt count
        //
        level1Count++;
    
        //
        // Read the low priority interrupt vector
        //
        vectorOffset = LIN_getInterruptLine1Offset(LINA_BASE);
        LIN_clearInterruptStatus(LINA_BASE, LIN_INT_ID);
        LIN_clearGlobalInterruptStatus(LINA_BASE, LIN_INTERRUPT_LINE1);
    
        //
        // Acknowledge this interrupt located in group 8
        //
        Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP8);
    }

    Let me know if any questions/concerns with this code.

    Regards,

    Vince

  • Hello Vince,

    Thank you for the example code. I will try this on the F280049C and let you know the results.

    Greetings,

    John

  • Hello Vince,

    I was able to get back to this issue today. Yuhoo! Now it is working. Thanks for the example. That really helped a lot.

    The only thing I changed in my code, was to move the code in the indefinite loop into the RAM section.These were the key lines that helped:

        while (1)
        {
            MainLoop();
        }//for / while
        
        and 
        
        
    #pragma CODE_SECTION(MainLoop, ".TI.ramfunc");
    static void MainLoop(void)
    {
       ... moved the code from the while(1) loop to here.
       }
    

    Then everything just starting working. Wow.

    Thanks again. Your sample code helped me a lot!

    Cheers,

    John