[NO ASF] Issue with SAMD21 LIN slave implementation on UART using break/sync detection

Go To Last Post
4 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello all,

 

The main issue is with LIN break/sync feature, mainly it reports "Inconsistent Sync Field" after "Receive Break" interrupt and fails to read a valid PID sent by the LIN master. 

Setup

The following figure shows the measurement of the LIN UART tx line with SALEAE logic analyzer. The Header seems correct, the baud in the master side is also set to 19.2kbps, as well the logic analyzers protocol analyzing baud rate

 

SALEAE Measurement

 

Code

#define MAIN_CLOCK_HZ 48000000 // 48MHz

void uart_init(void)
{
    /* Configure USART Tx pin as OUTPUT and assign pin mux */
    PORT->Group[PORTB].DIRSET.reg = PORT_PB12;
    PORT->Group[PORTB].PMUX[12>>1].bit.PMUXE = PORT_PMUX_PMUXE_C_Val;
    PORT->Group[PORTB].PINCFG[12].reg = PORT_PINCFG_INEN | PORT_PINCFG_PMUXEN;

    /* Configure USART Rx pin as INPUT and assign pin mux */
    PORT->Group[PORTB].DIRCLR.reg = PORT_PB13;
    PORT->Group[PORTB].PMUX[13>>1].bit.PMUXO = PORT_PMUX_PMUXE_C_Val;
    PORT->Group[PORTB].PINCFG[13].reg = PORT_PINCFG_PMUXEN | PORT_PINCFG_INEN;

    PM->APBCMASK.reg |= PM_APBCMASK_SERCOM4;

    /* Configure SERCOM4 to uses GCLK Generator 0 as source - core clock */
    GCLK->CLKCTRL.reg = (U16)(GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID_SERCOM4_CORE);
    while (GCLK->STATUS.bit.SYNCBUSY);

    SERCOM4->USART.CTRLA.bit.SWRST = 1u;
    while(SERCOM4->USART.SYNCBUSY.reg);

    // configure CTRLA
    SERCOM_USART_CTRLA_Type cfga =
    {
        .bit.CMODE   = 1,       // 1=asynchronous mode
        .bit.CPOL    = 0,       // XCLK polarity, rising->TX, falling->RX (sync mode)
        .bit.DORD    = 1,       // 1=LSB sent first (for LIN)
        .bit.ENABLE  = 0,       // enable (disable before settings), later
        .bit.FORM    = 4,       // 0=UART 1=+PARITY 4=AUTOBAUD 5=+PARITY, 4 has break-detection & auto-baud (for LIN), see STATUS.ISF
        .bit.IBON    = 0,       // immediate STATUS.BUFOVF
        .bit.MODE    = 1,       // 0=UART+XCLK, 1=UART, 2=SPI-slave, 3=SPI-master, 4=I2C-slave, 5=I2C-master
        .bit.RUNSTDBY= 1,       // run in standby
        .bit.RXPO    = 1,       // PAD[1], PIN_PB13
        .bit.TXPO    = 0,       // PAD[0], PIN_PB12
        .bit.SAMPA   = 0,       // SAMPle Adjustment to the right, 0=7/8/9, 1=+2, 2=+4, 3=+6
        .bit.SAMPR   = 1,       // baudrate & oversampling: 0=A16x, 1=F16x, 2=A8x, 3=F8x, 4=A3x, 5=F3x (A=Arithmetic, F=Fractional(=For LIN))
        .bit.SWRST   = 0,       // reset, other bits are ignored
    };
    SERCOM4->USART.CTRLA = cfga;
    while(SERCOM4->USART.SYNCBUSY.reg);

    // configure CTRLB
    SERCOM_USART_CTRLB_Type cfgb =
    {
        .bit.CHSIZE    = 0,     // character size: 8 bits
        .bit.COLDEN    = 0,     // disable collision detection
        .bit.ENC       = 0,     // IrDA encoding not applicable
        .bit.PMODE     = 0,     // parity not applicable
        .bit.RXEN      = 1,     // enable RX, see SYNCBUSY.CTRLB
        .bit.TXEN      = 1,     // enable TX, see SYNCBUSY.CTRLB
        .bit.SBMODE    = 0,     // set 1 stopbit
        .bit.SFDE      = 0,     // disable start of frame detection
    };
    SERCOM4->USART.CTRLB = cfgb;
    while(SERCOM4->USART.SYNCBUSY.reg);

    #define BAUDCONST8    ((MAIN_CLOCK_HZ * 8) / (16 * 19200))
    SERCOM4->USART.BAUD.FRAC.FP   = (BAUDCONST8 % 8);
    SERCOM4->USART.BAUD.FRAC.BAUD = (BAUDCONST8 / 8);
    while(SERCOM4->USART.SYNCBUSY.reg);

    SERCOM4->USART.INTENSET.reg = SERCOM_USART_INTENSET_RXC | SERCOM_USART_INTENSET_RXBRK;

    NVIC_SetPriority(SERCOM4_IRQn, 0u);
    NVIC_EnableIRQ(SERCOM4_IRQn);

    SERCOM4->USART.CTRLA.reg |= SERCOM_USART_CTRLA_ENABLE;
    while(SERCOM4->USART.SYNCBUSY.bit.ENABLE);
}

void SERCOM4_Handler(void)
{
    /* Temporary variables */
    U16 interrupt_status;

    while(SERCOM4->USART.SYNCBUSY.reg);

    /* Read and mask interrupt flag register */
    interrupt_status = SERCOM4->USART.INTFLAG.reg;
    interrupt_status &= SERCOM4->USART.INTENSET.reg;

    if (interrupt_status & SERCOM_USART_INTFLAG_RXBRK)
    {
        /* Break and sync must have been received at this time */

        // Get an hit here, but ISF is set in the status field
	SERCOM4->USART.INTFLAG.reg = SERCOM_USART_INTFLAG_RXBRK;
    }

    /* After the break/sync the LIN PID must be received */
    if (interrupt_status & SERCOM_USART_INTFLAG_RXC)
    {
        // Get here as well but the data is always 0xFF
        U16 tmp = (SERCOM4->USART.DATA.reg & SERCOM_USART_DATA_MASK);
    }
}

When I reconfigure the UART to work with plain UART .FORM = 0, .SAMPR = 0. Re calculate the baud 

U64 br = (U64)65536 * (F_CPU - 16 * baud) / F_CPU; // Variable for baud rate

Then I receive the sync byte 55h, the PID 06h but I also get the frame error, because of the 13 dominant bits.

 

I have run out of ideas to try.. did not even find a issue in errata. Although it mentioned that it might not set ISF if some stop bit error, but my case is the reverse- it is always set!

 

SEND HELP!!

Last Edited: Sat. Apr 4, 2020 - 09:57 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Update

The PID that I sent was 0x06 (0b0110 LBS first), I started testing with other PID´s and found out that PID´s starting with a 1 work ok so 0x0D (0b1101 LBS first) . I get the break/sync interrupt followed by the receive complete and can read out the PID.

This does not make sense for me, anyone understanding the problem? 

SALEAE Measurement

Is the header break delimiter too short from the master? Is the SAMD21 interpreting the additional bits from the PID as the SYNC byte? 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Update 2

Tested with CPU core clock set to internal 8 MHz clock so that the APBC clock connected to SERCOM is also 8 MHz. Still got the same problem as described in update 1

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi,

I just had the same issue on an Arduino MKRZero (SAMD21).

Only IDs starting with 1 worked, otherwise Inconsistent sync field (ISF) was raised in UART.STATUS register.

 

I came across this application note (for SAMDA1) that says in the code example at the end: break+autobaud will not operate with 1 stop bit following sync field...

 

Switching my LIN bus configuration from 8N1 to 8N2 (2 stop bits) solved my problem.

 

I however wasn't able to find any information on why 2 stops bits are needed and if another configuration could work with only 1 stop bit.