(ASF) LIN on USART SERCOM doesn't work (ATSAMC21N)

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

I tried to test LIN message format over USART on board SAMC21N. AtmelStart was used to make project.
 

  • This is test code :

 

#include <atmel_start.h>

 

//usart baud

#define CONF_SERCOM_2_USART_BAUD 9600

 

//usart descriptor

struct io_descriptor *io_usart;

//message

uint8_t msg[3]={0x00, 0x55, 0x12};
 

 

void USART_as_LIN_mode()
{    
    /*LIN master format (CTRLA.FORM = 0x02)*/
    hri_sercomspi_write_CTRLA_FORM_bf(SERCOM2, 0x02);
    //SERCOM2->USART.CTRLA.bit.FORM=0x02;
    
    /* Asynchronous Mode (CTRLA.CMODE = 0)*/
    hri_sercomusart_write_CTRLA_CMODE_bit(SERCOM2,0);
    //SERCOM2->USART.CTRLA.bit.CMODE=0x0;
    
    /*16x sample rate using fractional baud rate generation (CTRLA.SAMPR = 1)*/
    hri_sercomusart_write_CTRLA_SAMPR_bf(SERCOM2, 1);
    //SERCOM2->USART.CTRLA.bit.SAMPR=0x01;
    
     /*Software controls transmission of the LIN header(CTRLB.LINCMD = 0x01)*/
     hri_sercomusart_write_CTRLB_LINCMD_bf(SERCOM2, 0x01);
    //SERCOM2->USART.CTRLB.bit.LINCMD=0x01;
    
    /*Hardware controls transmission of the LIN header(CTRLB.LINCMD = 0x01)*/
    //hri_sercomusart_write_CTRLB_LINCMD_bf(SERCOM2, 0x02);
    //SERCOM2->USART.CTRLB.bit.LINCMD=0x02;
    
    /*Delay between break and sync transmission is 1 bit time, delay between sync and ID transmission is 1 bit time.*/
    //hri_sercomusart_write_CTRLC_HDRDLY_bf(SERCOM2,0x0);
    //SERCOM->USART.CTRLC.bit.HDRDLY=0x00;
    
    /*Length of the break field set as 13 bits (CTRLC.BRKLEN=0x0).*/
    //hri_sercomusart_write_CTRLC_BRKLEN_bf(SERCOM2, 0x0);
    //SERCOM2->USART.CTRLC.bit.BRKLEN=0x0;
    
 
 
 
}
void USART_init(void)
{
    usart_async_get_io_descriptor(&USART_1, &io_usart);
    usart_async_enable(&USART_1);    
}

int main(void)
{
    /* Initializes MCU, drivers and middleware */
    atmel_start_init();
    
    /*Initializes LIN mode*/
    USART_as_LIN_mode();
    
    /*Initializes USART*/
    USART_init();
    
    /**/
    io_write(io_usart, msg, 3); // uint8_t msg[3]={0x00, 0x55, 0x12};
     /*This function writes up to \p length of bytes to a given I/O descriptor.
     * It returns the number of bytes actually write.
     *
     * \param[in] descr  An I/O descriptor to write
     * \param[in] buf    The buffer pointer to story the write data
     * \param[in] length The number of bytes to write
     *
     * \return The number of bytes written*/
  

 
    while (1) {
    }
}

 

 

  • Part of datasheet about LIN over USART :

 

I tried software transmission control(CTRLB.LINCMD=0x01).

 

 

  • What I got on logic analyzer:

It looks like regular USART. For example: Break is not 13 bits long.

 

Last Edited: Thu. Sep 17, 2020 - 01:56 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi  jusupovic ,

Has your problem been solved?

I also have some problem with LIN driver.

I use the same way as the datasheet has described. However, the sercom still behaves like a USART.

My setting is as follows:

 

#include <atmel_start.h>

extern struct usart_async_descriptor USART_0;
hri_sercomusart_ctrla_reg_t sercomreg;
SERCOM_USART_CTRLA_Type ctrla_tmp;
SERCOM_USART_CTRLB_Type ctrlb_tmp;
void lin_init(void){    
    usart_async_disable(&USART_0);
    sercomreg = hri_sercomusart_get_CTRLA_reg(SERCOM3 , 0xffffffff);
    ctrla_tmp.reg =  sercomreg;
    ctrla_tmp.bit.FORM = 0x02;
    ctrla_tmp.bit.CMODE = 0x00;
    ctrla_tmp.bit.SAMPR = 1;
    SERCOM3->USART.CTRLA.reg =  ctrla_tmp.reg;
    while(SERCOM3->USART.SYNCBUSY.reg);
    if ( SERCOM3->USART.CTRLA.bit.FORM !=0x02 |
        SERCOM3->USART.CTRLA.bit.CMODE !=0x00|
        SERCOM3->USART.CTRLA.bit.SAMPR !=0x01  
        )
    {
        while(1);
    }
    usart_async_enable(&USART_0);
}

void lin_config(void){
    

    usart_async_disable(&USART_0);
    sercomreg = hri_sercomusart_get_CTRLB_reg(SERCOM3 ,0xffffffff);
    ctrlb_tmp.reg = sercomreg;
    ctrlb_tmp.bit.LINCMD=0x01;
    SERCOM3->USART.CTRLB.reg =  ctrlb_tmp.reg;
    while(SERCOM3->USART.SYNCBUSY.reg);
    /*
    if ( SERCOM3->USART.CTRLB.bit.LINCMD != 0x02
    )
    {
        while(1);
    }*/
    usart_async_enable(&USART_0);
}

void uart_init(void){
    usart_async_enable(&USART_0);
    
}

void lin_send(void)
{
    uint8_t data[4];
    struct io_descriptor *io;
    usart_async_get_io_descriptor(&USART_0, &io);
    
    data[0] = 0x00 ;
    data[1] = 0x55 ;
    data[2] = 0x03 ;
    io_write(io, data, 3);
}
    
    
    
    

int main(void)
{
    /* Initializes MCU, drivers and middleware */
    atmel_start_init();
    
    uart_init();
    lin_init();
    lin_config();
    

    /* Replace with your application code */
    gpio_set_pin_level(LIN_CS, 1);
    gpio_set_pin_level(EN_N3V3,1);
    gpio_set_pin_level(EN_P3V3,1);
    gpio_set_pin_level(EN_8V,1);

    while (1){
        //USART_0_example();
        
        lin_send();
        delay_ms(50);
    }
}
 

pinxian

Last Edited: Fri. Sep 18, 2020 - 07:37 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi , I had tested your code and I found that CTRLA  is not modified by   USART_as_LIN_mode().

 

pinxian

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

Thank you for reply @edxian, 
 

when I check with my debugger all register is set as it should be except strobe bits register(CTRLB.bit.LINCMD).

 

Last Edited: Mon. Sep 21, 2020 - 09:25 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi  jusupovic ,

Have you solved your problem. I still cant figure out how to solve the problem.

Thanks a lot!

pinxian

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


Hi all,

Finally, I got a solution for LIN when using asf start project:

 

1. make sure that the sampling rate changed to "fractional 16x" rather than "arithmatic 16x" when configuring UART instance.

2. copy the following code to your project.

 

#include <atmel_start.h>

#define LIN_SERCOM SERCOM4

extern struct usart_async_descriptor USART_0;

uint8_t tx_message_0[64];

uint8_t tx_message_1[64];

uint8_t tx_message_2[8] = {0};

void lin_init(void){

    

    hri_sercomusart_write_CTRLA_FORM_bf(LIN_SERCOM, 0x02);

    hri_sercomusart_write_CTRLA_CMODE_bit(LIN_SERCOM , 0);

    hri_sercomusart_write_CTRLA_SAMPR_bf(LIN_SERCOM,1);

    

}

void lin_break(void){

    hri_sercomusart_write_CTRLB_LINCMD_bf(LIN_SERCOM, 0x02);

    while(LIN_SERCOM->USART.SYNCBUSY.bit.CTRLB);

}

void lin_send_header(void)

{

    while(!LIN_SERCOM->USART.INTFLAG.bit.DRE);

    LIN_SERCOM->USART.DATA.reg = 0x32;

}



void lin_send_response(uint8_t*data, uint8_t len){

    for(unsigned int i=0;i<len;i++){

            while(!LIN_SERCOM->USART.INTFLAG.bit.DRE);

            LIN_SERCOM->USART.DATA.reg =data[i];

    }

}

void lin_send(void){

    uint8_t data[5] = {0x01,0x02,0x03,0x04,0xff};

    lin_break();

    lin_send_header();

    lin_send_response(data,5);

}

static uint8_t buffer[16];

int main(void)

{

    atmel_start_init();

    USART_0_init();

    lin_init();

    usart_async_enable(&USART_0);

    gpio_set_pin_level(LIN_EN,1);

    while (1) {

    lin_send();

    delay_ms(50);

    }

}

 

3. change the following macro depend on which SERCOM port you use.

For example, if you use SERCOM4 than the definition will be "#define LIN_SERCOM SERCOM4 ".

 

4.  enable your LIN tranciever by setting gpio state.

  gpio_set_pin_level(LIN_EN,1);

 

5. Enjoy it.  

 

BTW, I have tested it by the salaea logic analyzer and got correct packets . 

 

 

 

 

 

 

 

 

 

 

 

 

pinxian

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

Is the above one is for lin master?

dev

Last Edited: Wed. Sep 22, 2021 - 05:01 AM