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.

TMS320F280025: LIN Slave Response

Part Number: TMS320F280025

C2k Team,

I'm trying to do a LIN MITM attack on some equipment and am trying to write some drivers for the LIN peripheral.  It would appear there is ZERO documentation or examples of how to propely do a slave response.  The only things I've been able to find is this:

https://e2e.ti.com/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/1114621/tms320f280049c-lin-module-in-slave-mode---how-to-initiate-response-transmission

In the example posted here, the user is only able to respond to a single ID.  This example also is giving me vibes that the underlying state machine wants to see a TX ID match before it will allow a slave response?  Is this true?

I'm trying to write an interrupt based driver where I manage all the comms with the processor and don't use any filtering/masking.  I'm able to RX messages all day long.  When I get an ID interrupt that is for a slave response message I copy the data into the tx buffer but it never gets sent out and my isTxReady check fails after the first time around.

Here's my ISR:

__interrupt void
LIN_linAHandler(void)
{
    uint16_t interruptCause;

    //
    // Read the high priority interrupt vector
    //
    interruptCause = LIN_getInterruptLine0Offset(LINA_BASE);
    switch(interruptCause)
    {
    case LIN_VECT_ID:
    {
        linMessageObject_t *message;
        volatile uint16_t messageId;
        messageId = LIN_getRxIdentifier(LINA_BASE);
        message = LIN_linGetMessageObjectById(messageId);

        if(message != 0)
        {
            //Set frame length so it may be received correctly
            LIN_setFrameLength(LINA_BASE, message->len);

            //Calculate period
//            message->period = timer0getCount() - message->lastRxTime;
//            message->lastRxTime = timer0getCount();

            //If the message is TX its showtime baybee!
            if((message->direction == LINMESSAGE_TO_MASTER) && injectionActive)
            {
//                LIN_linTx(LINA_BASE, message);
                if(LIN_isTxReady(LINA_BASE))
                {
                    //
                    // Write data to Tx Buffer of LINA
                    //
                    LIN_sendData(LINA_BASE, message->originalData);
                }
            }

            //If the message is RX we are done
        }


        //Clear Interrupt Status
        LIN_clearInterruptStatus(LINA_BASE, LIN_INT_ID);
        break;
    }

    case LIN_VECT_RX:
    {
        linMessageObject_t *message;
        volatile uint16_t dumpBuffer[8];
        message = LIN_linGetMessageObjectById(LIN_getRxIdentifier(LINA_BASE));



        if(message != 0)
        {
            if((message->direction == LINMESSAGE_TO_SLAVE) )//|| !injectionActive)
            {
                LIN_getData(LINA_BASE, message->originalData);

            }else
            {
                //We gots a problem
                //Data in the rx buffer we don't know what to do with.
//                ESTOP0;
                LIN_getData(LINA_BASE, dumpBuffer);
            }
        }else
        {
            LIN_getData(LINA_BASE, dumpBuffer);
        }

        LIN_clearInterruptStatus(LINA_BASE, LIN_INT_RX);
        break;
    }
    case LIN_VECT_TX:
    {
        LIN_clearInterruptStatus(LINA_BASE, LIN_INT_TX);
        break;
    }
    case LIN_VECT_CE:
    {
        LIN_clearInterruptStatus(LINA_BASE, LIN_INT_CE);
//        ESTOP0;
        break;
    }
    case LIN_VECT_FE:
    {
        LIN_clearInterruptStatus(LINA_BASE, LIN_INT_FE);
//        ESTOP0;
        break;
    }
    case LIN_VECT_OE:
    {
        LIN_clearInterruptStatus(LINA_BASE, LIN_INT_OE);
//        ESTOP0;
        break;
    }
    case LIN_VECT_BE:
    {
        LIN_clearInterruptStatus(LINA_BASE, LIN_INT_BE);
//        ESTOP0;
        break;
    }
    case LIN_VECT_NRE:
    {
        LIN_clearInterruptStatus(LINA_BASE, LIN_INT_NRE);
//        ESTOP0;
        break;
    }
    case LIN_VECT_PBE:
    {
        LIN_clearInterruptStatus(LINA_BASE, LIN_INT_PBE);
//        ESTOP0;
        break;
    }
    default:
        ESTOP0;
    }


    LIN_clearGlobalInterruptStatus(LINA_BASE, LIN_INTERRUPT_LINE0);

    //
    // Acknowledge this interrupt located in group 8
    //
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP8);
}

Any idea what I'm doing wrong?  It's super duper frustrating when a key function like this isn't documented and there are no examples. Cry

  • Here's my init code in case that is helpful is debugging...

        SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_LINA);
    
        GPIO_setPinConfig(DEVICE_GPIO_CFG_LINA_TX);
        GPIO_setDirectionMode(DEVICE_GPIO_PIN_LINA_TX, GPIO_DIR_MODE_OUT);
        GPIO_setPadConfig(DEVICE_GPIO_PIN_LINA_TX, GPIO_PIN_TYPE_STD);
        GPIO_setQualificationMode(DEVICE_GPIO_PIN_LINA_TX, GPIO_QUAL_ASYNC);
    
        GPIO_setPinConfig(DEVICE_GPIO_CFG_LINA_RX);
        GPIO_setDirectionMode(DEVICE_GPIO_PIN_LINA_RX, GPIO_DIR_MODE_IN);
        GPIO_setPadConfig(DEVICE_GPIO_PIN_LINA_RX, GPIO_PIN_TYPE_STD);
        GPIO_setQualificationMode(DEVICE_GPIO_PIN_LINA_RX, GPIO_QUAL_ASYNC);
    
        //
        // 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, &LIN_linAHandler);
    
        //
        // Enable the LIN interrupt signals
        //
        Interrupt_enable(INT_LINA_0);
    
        //
        // Initialize the LIN module
        //
    
        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_enableAutomaticBaudrate(LINA_BASE);
    
        //
        // Use the set frame length and not ID4/ID5 bits for length control
        //
        LIN_setCommMode(LINA_BASE, LIN_COMM_LIN_USELENGTHVAL);
    //    LIN_setCommMode(LINA_BASE, LIN_COMM_LIN_ID4ID5LENCTL);
    
        //
        // Setup to continue operating on emulation suspend
        //
        LIN_setDebugSuspendMode(LINA_BASE, LIN_DEBUG_COMPLETE);
    
        //
        // Use Enhanced Checksum
        //
        LIN_setChecksumType(LINA_BASE, LIN_CHECKSUM_ENHANCED);
    
        //DISABLE CHECKSUM
        HWREG_BP(LINA_BASE + LIN_O_SCIGCR2) &= ~LIN_SCIGCR2_CC;
    
        //
        // 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);
    
        //
        // Set LIN interrupts to enabled
        //
        LIN_disableInterrupt(LINA_BASE, LIN_INT_ALL);
        LIN_enableInterrupt(LINA_BASE, LIN_INT_RX);
        LIN_enableInterrupt(LINA_BASE, LIN_INT_ID);
        LIN_enableInterrupt(LINA_BASE, LIN_INT_CE);
        LIN_enableInterrupt(LINA_BASE, LIN_INT_FE);
        LIN_enableInterrupt(LINA_BASE, LIN_INT_OE);
        LIN_enableInterrupt(LINA_BASE, LIN_INT_BE);
        LIN_enableInterrupt(LINA_BASE, LIN_INT_NRE);
        LIN_enableInterrupt(LINA_BASE, LIN_INT_PBE);
    
        LIN_setInterruptLevel0(LINA_BASE, LIN_INT_ALL);
    
    
        LIN_enableGlobalInterrupt(LINA_BASE, LIN_INTERRUPT_LINE0);
        LIN_clearGlobalInterruptStatus(LINA_BASE, LIN_INTERRUPT_LINE0);
    
        //
        // Set Baud Rate Settings - 100MHz Device
        //
        LIN_setBaudRatePrescaler(LINA_BASE, 96U, 11U);
        LIN_setMaximumBaudRate(LINA_BASE, 100000000U);
    
        //
        // Set response field to 1 byte
        //
        LIN_setFrameLength(LINA_BASE, 1U);
    
        //
        // Configure sync field
        // Sync break (13 + 5 = 18 Tbits)
        // Sync delimiter (1 + 3 = 4 Tbits)
        //
        LIN_setSyncFields(LINA_BASE, 5U, 3U);
    
        //
        // Set Mask ID so TX/RX match will always happen
        //
        LIN_setTxMask(LINA_BASE, 0xFFU);
        LIN_setRxMask(LINA_BASE, 0xFFU);
    
        //
        // Disable IODFT testing and external loopback mode
        //
        LIN_disableExtLoopback(LINA_BASE);
    
        //
        // Finally exit SW reset and enter LIN ready state
        //
        LIN_exitSoftwareReset(LINA_BASE);
    
        EDIS;

  • I made a little progress on this.  I'm on a vehicle with a 24V system voltage.  As such I'm powering my board with 24V so my LIN node is operating at that level.  I guess I wasn't paying close enough attention because I missed that the rest of the vehicle's LIN bus is operating at 12V.  Swapping my board over to a 12V supply appears to have caused my board to be able to start replying to messages as a slave.  Still need a little more time to fully validate, but I think this is the root cause of my issues.

    I would still ask that this function is elaborated on in the TRM and that examples are provided.

  • Hi Trey,

    The C2000 LIN not having a slave example is definitely a gap and something we are trying to get fixed in later software releases, thank you for bringing this to our attention and I apologize for the frustration. I can also make sure this is updated in documentation if there are any future refreshes of the TRM. 

    Let me know if you have any additional questions after doing some more validation. 

    Best Regards,

    Delaney