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.

MSPM0L1306: Issue with LIN demo code lin_responder (tx&rx abnormal accidental when LIN master restart or slave repower)

Part Number: MSPM0L1306
Other Parts Discussed in Thread: SYSCONFIG

Tool/software:

Hello

I run demo code lin_responder with MSPM0L1306 LaunchPad Development Kit. The LIN master is Vector VN1630.

There are little change with demo code, see below pictures. 

The TX and RX is abnormal and can not recover when enter else condition after DL_UART_EXTEND_IIDX_RX interrupt.

It happens accidental when LIN master start stop periodic with LIN slave keep power on, or happens accidental when LIN slave power on off periodic with LIN master keep work.

Why received SYNC byte is not 0x55? What function can be invoked to restart LIN, I try to use DL_UART_Extend_reset() but no change.

  • Hi Bian,
    Why are you setting all of your PID as zero when you calculate your checksum? I think this will mess with your LIN communication since the checksum should include the PID into its calculation. As in the else condition you mentioned, it seems the state the original example had is StateMachine = LIN_STATE_WAIT_FOR_BREAK; rather than LIN_STATE_BREAK_FIELD. I recommend putting the original state from the example and see if it fixes the issue. I also recommend leaving the gAutoBaudUsed option in there since it can sometimes help avoid this kinds of wrong functionality. You can use DL_UART_Extend_reset() or toggle the power of the module, but you'll need to re-configure the UART LIN module.

    Best Regards,

    Diego Abad

  • Hi Diego,

    thanks for your info.

    The PID 0x3C and 0x3D are classic checksum.

    The variable StateMachine has been set as original state LIN_STATE_WAIT_FOR_BREAK, but the issue is also.

    Where is gAutoBaudUsed option? i does not find auto buad in TRM? Does MSPM0L1306 support auto buad?

    What function must be invoked for reset LIN? I use SYSCFG_DL_LIN_0_init(), but it does not work.

    I find the time of sync is invalid when issue happen, enter else condition in below picture.

    thank!

    johnny

     

  • Hi Bian,
    The auto baud rate is an option handled through a process inside the code that most of our examples have by default. Here's a link to the code you can copy for this device. 

    You will use the reset function or the turn off/turn on functions to reset the UART-LIN Module. However, once you do this, you'll need to reconfigure it. You can find those functions inside the ti_dl_sysconfig.c file. 

    Best Regards,

    Diego Abad

  • Hi Diego,

    I add code in else of rising edge interrupt detection, the issue seems fixed. Please help confirm if there is potential risk with the change. Thanks!

    br

    johnny

  • Hi Bian,
    I don't think there should be an issue with that. Glad to hear the code seems to be working.

    Best Regards,

    Diego bad

  • Hi Diego,

    The tx frame 0x3D accidental has checksum error. I try some method, such as change disable/enable rx interrupt position. Please help check code for possible reason. It's also most the same as demo code 'lin_commander_LP_MSPM0L1306_nortos_ticlang'. thanks!

    const uint8_t LIN_Channel = 0;
    
    volatile LIN_STATE gStateMachine = LIN_STATE_WAIT_FOR_BREAK;
    volatile uint8_t gNumCycles      = 0;
    volatile LIN_Sync_Bits gBitTimes[LIN_RESPONDER_SYNC_CYCLES];
    // Buffer for received LIN data
    uint8_t gResponderRXBuffer[LIN_DATA_MAX_BUFFER_SIZE] = {0};
    // Buffer for transmitted LIN data
    volatile static uint8_t gResponderTXBuffer[LIN_DATA_MAX_BUFFER_SIZE] = {0};
    
    /* Variables for autobaud feature */
    volatile uint8_t gNumSyncErrors        = 0;
    volatile bool gFirstSyncBit            = true;
    volatile uint16_t gTotalBitTime        = 0;
    volatile uint16_t gLinResponseLapseVar = LIN_RESPONSE_LAPSE;
    volatile bool gAutoBaudUsed            = false;
    volatile uint32_t gLin0TbitWidthVar    = LINUART0_TBIT_WIDTH;
    volatile uint16_t gPrevBaudRate        = LINUART0_BAUD_RATE;
    volatile uint16_t gCurrBaudRate        = LINUART0_BAUD_RATE;
    
    volatile static uint16_t pos_edge_counter = 0;
    
    
    void LIN_RxIndication(void)
    {
    //    memcpy(&gResponderTXBuffer[0], &gResponderRXBuffer[0], 0x08);
    
        // SDK interface, it's invoked after rx
        LinIf_RxIndication(LIN_Channel, &gResponderRXBuffer[0]);
    }
    
    // Definition of LIN frame
    LIN_table_record_t responderMessageTable[LIN_RESPONDER_NUM_MSGS] =
    {
        /* Important, connection number matches the order of this table */
        {
            0x3C, /* PID 0x3C */
            8,
            LIN_RxIndication
        },
        {
            0x7D, /* PID 0x3D */
            8,
        },
    };
    
    
    /*******************************************************************************
     *                      Public function Declaration
     ******************************************************************************/
    
    
    /**
     *  @brief  write data into target address
     *
     *  The target address for a command must be flash word (64-bit) aligned. This
     *  means that the target address must be aligned to a 0b000 boundary (for
     *  example, the 3 LSBs in the address must be zero).
     *  @param  Address: Address of flash
     *  @param  Write_Data: bytes of write data
     *  @retval write state
     **/
    void setLINResponderRXMessage(uint8_t data, volatile LIN_STATE *gStateMachine)
    {
        static uint8_t msgTableIndex = 0;
        static uint8_t byteCounter   = 0;
        static LIN_word_t tempChksum;
        static LIN_RX_STATE LIN_state = LIN_RX_STATE_ID;
        volatile uint8_t checksum;
        uint8_t rxChecksum;
        UART_Regs *uart = LINUART0_INST;
        LIN_function_ptr_t callbackFunction;
        Lin_PduType PduPtr;
    
        switch (LIN_state) {
            case LIN_RX_STATE_ID:
                /* Find ID message */
                for (msgTableIndex = 0; msgTableIndex < LIN_RESPONDER_NUM_MSGS; msgTableIndex++)
                {
                    if (responderMessageTable[msgTableIndex].msgID == data)
                    {
                        // Found right ID
                        break;
                    }
                }
    
                if (msgTableIndex >= LIN_RESPONDER_NUM_MSGS) {
                    data = LIN_MESSAGE_NOT_FOUND;
                }
    
                // SDK interface, it's invoked after received LIN header
                PduPtr.Pid = data;
                PduPtr.Cs = LIN_CLASSIC_CS;
                PduPtr.SduPtr = &gResponderTXBuffer[0];
    
                LinIf_HeaderIndication(LIN_Channel, &PduPtr);
    
                switch (PduPtr.Drc)
                {
                    case LIN_FRAMERESPONSE_RX: /* ID 0x3C */
                        tempChksum.word = 0x00; //data;
                        byteCounter     = 0;
                        LIN_state       = LIN_RX_STATE_DATA;
                        *gStateMachine  = LIN_STATE_DATA_FIELD;
                        break;
    
                    case LIN_FRAMERESPONSE_TX: /* ID 0x3D */
                        /*
                         * Delay is used to ensure STOP bit after PID is completely
                         * received before data transmitted.
                         */
                        /* Disable LIN RX */
                        DL_UART_Extend_disableInterrupt(uart, DL_UART_EXTEND_INTERRUPT_RX);
    
                        delay_cycles(gLinResponseLapseVar);
                        HAL_TransmitFrame(gResponderTXBuffer);
    
                        *gStateMachine = LIN_STATE_WAIT_FOR_BREAK;
                        LIN_state      = LIN_RX_STATE_ID;
    
                        /* Enable LIN RX */
                        DL_UART_Extend_clearInterruptStatus(uart, DL_UART_EXTEND_INTERRUPT_RX);
                        DL_UART_Extend_enableInterrupt(uart, DL_UART_EXTEND_INTERRUPT_RX);
    
                        // SDK interface, it's invoked after tx
                        LinIf_TxConfirmation(LIN_Channel);
                        break;
                    default:
                        *gStateMachine = LIN_STATE_WAIT_FOR_BREAK;
                        break;
                }
                break;
    
            case LIN_RX_STATE_DATA:
                gResponderRXBuffer[byteCounter] = data;
                tempChksum.word += gResponderRXBuffer[byteCounter];
                byteCounter++;
    
                if (byteCounter >= responderMessageTable[msgTableIndex].msgSize) {
                    LIN_state = LIN_RX_STATE_CHECKSUM;
                }
                break;
    
            case LIN_RX_STATE_CHECKSUM:
                rxChecksum = data;
    
                tempChksum.word = tempChksum.byte[0] + tempChksum.byte[1];
                checksum        = tempChksum.byte[0];
                checksum += tempChksum.byte[1];
                checksum = 0xFF - checksum;
    
                if (rxChecksum == checksum) {
                    callbackFunction = responderMessageTable[msgTableIndex].callbackFunction;
                    callbackFunction();
                }
    
                /* Clear break field and sync byte flags */
                *gStateMachine = LIN_STATE_WAIT_FOR_BREAK;
                LIN_state      = LIN_RX_STATE_ID;
                break;
            default:
                LIN_state = LIN_RX_STATE_ID;
                break;
        }
    }
    
    /**
     *  @brief  Transmit LIN frame.
     *
     *  @param  *msgBuffer: data for transmit
     *  @retval void
     **/
    void HAL_TransmitFrame(uint8_t *msgBuffer)
    {
        uint8_t locIndex;
        volatile uint8_t checksum;
        volatile LIN_word_t tempChksum;
        UART_Regs *uart = LINUART0_INST;
        volatile uint8_t tempBuff[9];
    
        /* Disable LIN RX */
    //    DL_UART_Extend_disableInterrupt(uart, DL_UART_EXTEND_INTERRUPT_RX);
    
        tempChksum.word = 0x0000;//responderMessageTable[tableIndex].msgID;
        tempChksum.word = tempChksum.byte[0] + tempChksum.byte[1];
    
        for (locIndex = 0; locIndex < responderMessageTable[LIN_RESPONDER_TX_INDEX].msgSize; locIndex++)
        {
       //     DL_UART_Extend_transmitDataBlocking(uart, msgBuffer[locIndex]);
            tempBuff[locIndex] = msgBuffer[locIndex];
            tempChksum.word += msgBuffer[locIndex];
        }
        /* Calculate and send checksum */
      //  checksum = tempChksum.byte[0];
      //  checksum += tempChksum.byte[1];
      //  checksum = 0xFF - checksum;
    
        checksum = (uint8_t)(~(tempChksum.word % 0xFF));
        tempBuff[8] = checksum;
    
        for (locIndex = 0; locIndex < (responderMessageTable[LIN_RESPONDER_TX_INDEX].msgSize + 1); locIndex++)
        {
            DL_UART_Extend_transmitDataBlocking(uart, tempBuff[locIndex]);
       //     delay_cycles(512);
        }
    //    delay_cycles(50);
     //   DL_UART_Extend_transmitDataBlocking(uart, checksum);
        while (DL_UART_Extend_isBusy(uart)) {
            ;
        }
        delay_cycles(50);
    
        // SDK interface, it's invoked after tx
     //   LinIf_TxConfirmation(LIN_Channel);
    
        DL_UART_Extend_receiveDataBlocking(uart);
    
        /* Enable LIN RX */
    //    DL_UART_Extend_clearInterruptStatus(uart, DL_UART_EXTEND_INTERRUPT_RX);
    //    DL_UART_Extend_enableInterrupt(uart, DL_UART_EXTEND_INTERRUPT_RX);
    }
    
    /*
       @brief  This function is to handle LIN Interrupt.
       @param  void
       @retval void
     */
    void LINUART0_INST_IRQHandler(void)
    {
        uint16_t counterVal = 0;
        volatile uint8_t data = 0;
        uint16_t averageBitTime   = 0;
        uint16_t measuredBaudRate = 0;
    	
        switch (DL_UART_Extend_getPendingInterrupt(LINUART0_INST)) {
            /* LIN Minimum Break Field Width Interrupt. */
            case DL_UART_EXTEND_IIDX_LIN_FALLING_EDGE:
                /* Signals the start of the break field. */
                if (gStateMachine == LIN_STATE_WAIT_FOR_BREAK) {
                    gStateMachine = LIN_STATE_BREAK_FIELD;
    
                    counterVal = DL_UART_Extend_getLINCounterValue(LINUART0_INST);
    
                    /* Validation check of the length of the break field. */
                    if (counterVal < (gLin0TbitWidthVar * 13.5) &&
                        counterVal >
                            (gLin0TbitWidthVar * LINUART0_TBIT_COUNTER_COEFFICIENT))
    
                    {
                        gStateMachine = LIN_STATE_SYNC_FIELD_NEG_EDGE;
                        DL_UART_Extend_enableLINCounterClearOnFallingEdge(
                                LINUART0_INST);
                        DL_UART_Extend_enableInterrupt(
                                LINUART0_INST, DL_UART_EXTEND_INTERRUPT_RXD_NEG_EDGE);
                        DL_UART_Extend_enableLINSyncFieldValidationCounterControl(
                                LINUART0_INST);
                    }
                    else {
                        gStateMachine = LIN_STATE_WAIT_FOR_BREAK;
                    }
    
                    DL_UART_Extend_disableInterrupt(
                            LINUART0_INST, DL_UART_EXTEND_INTERRUPT_RX);
                }
                break;
            /* Rising Edge Detection Interrupt on UARTxRXD. */
            case DL_UART_EXTEND_IIDX_RXD_POS_EDGE:
                /* Signals the positive edge of a sync field segment. */
                if (gStateMachine == LIN_STATE_SYNC_FIELD_POS_EDGE) {
                    gBitTimes[gNumCycles].posEdge =
                        DL_UART_Extend_getLINRisingEdgeCaptureValue(LINUART0_INST);
                    /* Validation check of the timing of the sync field segment.
                     * Finding an invalid sync bit stores each bit time to
                     * calculate new baud rate */
                    if (gBitTimes[gNumCycles].posEdge >
                            ((gLin0TbitWidthVar * 95) / 100) &&
                        gBitTimes[gNumCycles].posEdge <
                            ((gLin0TbitWidthVar * 105) / 100)) {
                        gNumCycles++;
                    } else if (!gFirstSyncBit) {
                        gTotalBitTime =
                            gTotalBitTime + gBitTimes[gNumCycles].posEdge;
                        gNumSyncErrors++;
                    } else {
                        gFirstSyncBit = false;
                    }
    
                    /* Only 5 segments of a sync field. */
                    if ((gNumSyncErrors + gNumCycles) ==
                        LIN_RESPONDER_SYNC_CYCLES) {
                        DL_UART_Extend_enableInterrupt(
                                LINUART0_INST, DL_UART_EXTEND_INTERRUPT_RX);
                        DL_UART_Extend_disableInterrupt(
                                LINUART0_INST, DL_UART_EXTEND_INTERRUPT_RXD_NEG_EDGE);
    
                        /* Track new and previous baud rate for validation when
                         * increasing baud rate. Ensures that resets to deal with
                         * overrun errors happen on the appropriate frame.
                         * Reset all variables relevant to sync field */
                        if (gNumCycles == LIN_RESPONDER_SYNC_CYCLES) {
                            gPrevBaudRate = gCurrBaudRate;
                            gAutoBaudUsed = false;
                        }
                        gNumCycles     = 0;
                        gNumSyncErrors = 0;
                        gTotalBitTime  = 0;
                        gFirstSyncBit  = true;
    
                        /* If 4 sync errors are detected, update baud rate given
                     * autobaud is enabled*/
    
                    } else if ((gNumSyncErrors == AUTO_BAUD_THRESHOLD) &&
                               AUTO_BAUD_ENABLED) {
                        averageBitTime   = gTotalBitTime / gNumSyncErrors;
                        measuredBaudRate = LINUART0_INST_FREQUENCY / averageBitTime;
    
                        DL_UART_disable(LINUART0_INST);
                        delay_cycles(AUTO_BAUD_CONFIG_DELAY);
                        DL_UART_disableFIFOs(LINUART0_INST);
                        gLinResponseLapseVar =
                                LINUART0_INST_FREQUENCY / (2 * measuredBaudRate);
                        gLin0TbitWidthVar = averageBitTime;
                        DL_UART_configBaudRate(
                            LINUART0_INST, LINUART0_INST_FREQUENCY, measuredBaudRate);
    
                        DL_UART_Extend_setLINCounterCompareValue(LINUART0_INST,
                            gLin0TbitWidthVar * LINUART0_TBIT_COUNTER_COEFFICIENT);
                        DL_UART_Extend_enable(LINUART0_INST);
                        gPrevBaudRate = gCurrBaudRate;
                        gCurrBaudRate = measuredBaudRate;
    
                        gAutoBaudUsed = true;
                        gStateMachine = LIN_STATE_SYNC_FIELD_NEG_EDGE;
                    }
                    else {
                        gStateMachine = LIN_STATE_SYNC_FIELD_NEG_EDGE;
                    }
                }
                else if (gStateMachine == LIN_STATE_SYNC_FIELD_NEG_EDGE)
                {
    #if 1
                    pos_edge_counter++;
                    if (pos_edge_counter >= 10)
                    {
                        pos_edge_counter = 0;
    
                        gNumCycles     = 0;
                        gStateMachine = LIN_STATE_WAIT_FOR_BREAK;
    
                        DL_UART_Extend_reset(LINUART0_INST);
                        DL_UART_Extend_enablePower(LINUART0_INST);
                        delay_cycles(POWER_STARTUP_DELAY);
    
                        SYSCFG_DL_LINUART0_init();
                        delay_cycles(512);
                    }
    #endif
                }
                break;
            /* Counter Overflow Interrupt. */
            case DL_UART_EXTEND_IIDX_LIN_COUNTER_OVERFLOW:
                gStateMachine = LIN_STATE_WAIT_FOR_BREAK;
                break;
            /* Negative Edge Detection Interrupt on UARTxRXD. */
            case DL_UART_EXTEND_IIDX_RXD_NEG_EDGE:
                /* Signals the negative edge of a sync field segment. */
                if (gStateMachine == LIN_STATE_SYNC_FIELD_NEG_EDGE) {
                    /* If flag for overrun has gone off and previous
                     * baud rate < current baud rate, turn counter off and on. */
                    if ((gCurrBaudRate > gPrevBaudRate) &&
                        DL_UART_getErrorStatus(
                            LINUART0_INST, DL_UART_ERROR_OVERRUN)) {
                        DL_UART_disableLINCounter(LINUART0_INST);
                        DL_UART_enableLINCounter(LINUART0_INST);
                    }
                    gBitTimes[gNumCycles].negEdge =
                        DL_UART_Extend_getLINFallingEdgeCaptureValue(LINUART0_INST);
                    gStateMachine = LIN_STATE_SYNC_FIELD_POS_EDGE;
                }
                break;
            /* UARTxRX Data Detection Interrupt. */
            case DL_UART_EXTEND_IIDX_RX:
    
                /* Determine if SYNC byte was received */
                if (gStateMachine == LIN_STATE_SYNC_FIELD_POS_EDGE) {
                    data = DL_UART_Extend_receiveData(LINUART0_INST);
    
                    if (data == LIN_SYNC_BYTE) {
                        /* First received byte is SYNC. Ignore it and wait for PID */
                        gStateMachine = LIN_STATE_PID_FIELD;
                    } else if ((data != LIN_SYNC_BYTE) && gAutoBaudUsed) {
                        /* Incorrect baud rate can cause an incorrect sync byte to be received.
                         * If autobaud was used and the sync byte was incorrect, the state machine
                         * proceeds as usual.*/
                        gStateMachine = LIN_STATE_PID_FIELD;
                    } else {
                        /* Unexpected byte, return to idle status */
                        gStateMachine = LIN_STATE_WAIT_FOR_BREAK;
                    }
                }
                else if (gStateMachine == LIN_STATE_PID_FIELD) {
                    data = DL_UART_Extend_receiveData(LINUART0_INST);
    
                    /* Process the PID. The state machine will be updated */
                    setLINResponderRXMessage(data, &gStateMachine);
                }
                /* Signals the data field */
                else if (gStateMachine == LIN_STATE_DATA_FIELD) {
                    data = DL_UART_Extend_receiveData(LINUART0_INST);
    
                    /*
                     *  Process data byte.
                     *  If data byte matches ID byte from "responderMessageTable"
                     *  then performs the matching function. Otherwise does nothing.
                     */
                    setLINResponderRXMessage(data, &gStateMachine);
                }
                /* Flushes any data that comes after an invalid PID*/
                else if (gStateMachine == LIN_STATE_WAIT_FOR_BREAK) {
                    data = DL_UART_Extend_receiveData(LINUART0_INST);
                }
                break;
            default:
                break;
        }
    }

    br

    johnny

  • Hi Bian,

    I would recommend to debug the code so that you make sure that each data that you receive is the correct data, and see why the checksum gives you the wrong value. I do see that you have one way to find the checksum different from the example, but I'm not 100% sure if it affects the end result for checking the incoming checksum and that checksum you calculate there (lines 184 to 199). However, I would recommend to use two different checksum variables to avoid mixing values from those two processes.

    Best Regards,

    Diego Abad

  • Hi Diego,

    The issue is resolved.

    There are 3 changes in demo code 'lin_commander_LP_MSPM0L1306_nortos_ticlang' of mspm0_sdk_2_06_00_05.

    1, calculation formula of checksum;

    2, reinit must be invoked when rising edge interrupt happen and gStateMachine == LIN_STATE_SYNC_FIELD_NEG_EDGE;

    3, disable rx interrupt is invoked after receive break field