Microchip® Advanced Software Framework

Quick Start Guide for SERCOM USART LIN

The supported board list:

  • SAMC21 Xplained Pro

This quick start will set up LIN frame format transmission according to your configuration CONF_LIN_NODE_TYPE. For LIN master, it will send LIN command after startup. For LIN salve, once received a format from LIN master with ID LIN_ID_FIELD_VALUE, it will reply four data bytes plus a checksum.

Setup

Prerequisites

When verify data transmission between LIN master and slave, two boards are needed: one is for LIN master and the other is for LIN slave. connect LIN master LIN PIN with LIN slave LIN PIN.

Code

Add to the main application source file, outside of any functions:

static struct usart_module cdc_instance,lin_instance;
#define LIN_ID_FIELD_VALUE 0x64
#define LIN_DATA_LEN 5
static uint8_t rx_buffer[LIN_DATA_LEN]={0};
const static uint8_t tx_buffer[LIN_DATA_LEN]={0x4a,0x55,0x93,0xe5,0xe6};

Copy-paste the following setup code to your user application:

static void configure_usart_cdc(void)
{
struct usart_config config_cdc;
config_cdc.baudrate = 115200;
config_cdc.mux_setting = EDBG_CDC_SERCOM_MUX_SETTING;
config_cdc.pinmux_pad0 = EDBG_CDC_SERCOM_PINMUX_PAD0;
config_cdc.pinmux_pad1 = EDBG_CDC_SERCOM_PINMUX_PAD1;
config_cdc.pinmux_pad2 = EDBG_CDC_SERCOM_PINMUX_PAD2;
config_cdc.pinmux_pad3 = EDBG_CDC_SERCOM_PINMUX_PAD3;
stdio_serial_init(&cdc_instance, EDBG_CDC_MODULE, &config_cdc);
usart_enable(&cdc_instance);
}
static void lin_read_callback(struct usart_module *const usart_module)
{
uint8_t i = 0;
if (CONF_LIN_NODE_TYPE == LIN_MASTER_NODE) {
for(i = 0; i < LIN_DATA_LEN; i++){
if(rx_buffer[i] != tx_buffer[i]) {
printf("Data error\r\n");
break;
}
}
if(i == LIN_DATA_LEN){
printf("Slave response: OK\r\n");
}
} else if (CONF_LIN_NODE_TYPE == LIN_SLAVE_NODE) {
if(rx_buffer[0] == LIN_ID_FIELD_VALUE) {
printf("Receive ID field from mater: OK \r\n");
usart_write_buffer_job(&lin_instance,
(uint8_t *)tx_buffer, LIN_DATA_LEN);
}
}
}
static void lin_read_error_callback(struct usart_module *const usart_module)
{
printf("Data Read error\r\n");
}
static void configure_usart_lin(void)
{
struct port_config pin_conf;
pin_conf.direction = PORT_PIN_DIR_OUTPUT;
port_pin_set_config(LIN_EN_PIN, &pin_conf);
/* Enable LIN module*/
port_pin_set_output_level(LIN_EN_PIN, 1);
struct usart_config config_lin;
/* LIN frame format*/
config_lin.lin_node = CONF_LIN_NODE_TYPE;
config_lin.transfer_mode = USART_TRANSFER_ASYNCHRONOUSLY;
config_lin.sample_rate = USART_SAMPLE_RATE_16X_FRACTIONAL;
config_lin.baudrate = 115200;
config_lin.mux_setting = LIN_USART_SERCOM_MUX_SETTING;
config_lin.pinmux_pad0 = LIN_USART_SERCOM_PINMUX_PAD0;
config_lin.pinmux_pad1 = LIN_USART_SERCOM_PINMUX_PAD1;
config_lin.pinmux_pad2 = LIN_USART_SERCOM_PINMUX_PAD2;
config_lin.pinmux_pad3 = LIN_USART_SERCOM_PINMUX_PAD3;
/* Disable receiver and transmitter */
config_lin.receiver_enable = false;
config_lin.transmitter_enable = false;
if (CONF_LIN_NODE_TYPE == LIN_SLAVE_NODE) {
config_lin.lin_slave_enable = true;
}
while (usart_init(&lin_instance,
LIN_USART_MODULE, &config_lin) != STATUS_OK) {
}
usart_enable(&lin_instance);
usart_register_callback(&lin_instance,
lin_read_callback, USART_CALLBACK_BUFFER_RECEIVED);
usart_register_callback(&lin_instance,
lin_read_error_callback, USART_CALLBACK_ERROR);
}

Add to user application initialization (typically the start of main()):

configure_usart_cdc();

Workflow

  1. Create USART CDC and LIN module software instance structure for the USART module to store the USART driver state while it is in use.
    static struct usart_module cdc_instance,lin_instance;
  2. Define LIN ID field for header format.
    #define LIN_ID_FIELD_VALUE 0x64
    Note
    The ID LIN_ID_FIELD_VALUE is eight bits as [P1,P0,ID5...ID0], when it's 0x64, the data field length is four bytes plus a checksum byte.
  3. Define LIN RX/TX buffer.
    #define LIN_DATA_LEN 5
    static uint8_t rx_buffer[LIN_DATA_LEN]={0};
    const static uint8_t tx_buffer[LIN_DATA_LEN]={0x4a,0x55,0x93,0xe5,0xe6};
    Note
    For tx_buffer and rx_buffer, the last byte is for checksum.
  4. Configure the USART CDC for output message.
    static void configure_usart_cdc(void)
    {
    struct usart_config config_cdc;
    config_cdc.baudrate = 115200;
    config_cdc.mux_setting = EDBG_CDC_SERCOM_MUX_SETTING;
    config_cdc.pinmux_pad0 = EDBG_CDC_SERCOM_PINMUX_PAD0;
    config_cdc.pinmux_pad1 = EDBG_CDC_SERCOM_PINMUX_PAD1;
    config_cdc.pinmux_pad2 = EDBG_CDC_SERCOM_PINMUX_PAD2;
    config_cdc.pinmux_pad3 = EDBG_CDC_SERCOM_PINMUX_PAD3;
    stdio_serial_init(&cdc_instance, EDBG_CDC_MODULE, &config_cdc);
    usart_enable(&cdc_instance);
    }
  5. Configure the USART LIN module.
    static void lin_read_callback(struct usart_module *const usart_module)
    {
    uint8_t i = 0;
    if (CONF_LIN_NODE_TYPE == LIN_MASTER_NODE) {
    for(i = 0; i < LIN_DATA_LEN; i++){
    if(rx_buffer[i] != tx_buffer[i]) {
    printf("Data error\r\n");
    break;
    }
    }
    if(i == LIN_DATA_LEN){
    printf("Slave response: OK\r\n");
    }
    } else if (CONF_LIN_NODE_TYPE == LIN_SLAVE_NODE) {
    if(rx_buffer[0] == LIN_ID_FIELD_VALUE) {
    printf("Receive ID field from mater: OK \r\n");
    usart_write_buffer_job(&lin_instance,
    (uint8_t *)tx_buffer, LIN_DATA_LEN);
    }
    }
    }
    static void lin_read_error_callback(struct usart_module *const usart_module)
    {
    printf("Data Read error\r\n");
    }
    static void configure_usart_lin(void)
    {
    struct port_config pin_conf;
    pin_conf.direction = PORT_PIN_DIR_OUTPUT;
    port_pin_set_config(LIN_EN_PIN, &pin_conf);
    /* Enable LIN module*/
    port_pin_set_output_level(LIN_EN_PIN, 1);
    struct usart_config config_lin;
    /* LIN frame format*/
    config_lin.lin_node = CONF_LIN_NODE_TYPE;
    config_lin.transfer_mode = USART_TRANSFER_ASYNCHRONOUSLY;
    config_lin.sample_rate = USART_SAMPLE_RATE_16X_FRACTIONAL;
    config_lin.baudrate = 115200;
    config_lin.mux_setting = LIN_USART_SERCOM_MUX_SETTING;
    config_lin.pinmux_pad0 = LIN_USART_SERCOM_PINMUX_PAD0;
    config_lin.pinmux_pad1 = LIN_USART_SERCOM_PINMUX_PAD1;
    config_lin.pinmux_pad2 = LIN_USART_SERCOM_PINMUX_PAD2;
    config_lin.pinmux_pad3 = LIN_USART_SERCOM_PINMUX_PAD3;
    /* Disable receiver and transmitter */
    config_lin.receiver_enable = false;
    config_lin.transmitter_enable = false;
    if (CONF_LIN_NODE_TYPE == LIN_SLAVE_NODE) {
    config_lin.lin_slave_enable = true;
    }
    while (usart_init(&lin_instance,
    LIN_USART_MODULE, &config_lin) != STATUS_OK) {
    }
    usart_enable(&lin_instance);
    usart_register_callback(&lin_instance,
    lin_read_callback, USART_CALLBACK_BUFFER_RECEIVED);
    usart_register_callback(&lin_instance,
    lin_read_error_callback, USART_CALLBACK_ERROR);
    }
    Note
    The LIN frame format can be configured as master or slave, refer to CONF_LIN_NODE_TYPE .

Use Case

Code

Copy-paste the following code to your user application:

configure_usart_lin();
if (CONF_LIN_NODE_TYPE == LIN_MASTER_NODE) {
printf("LIN Works in Master Mode\r\n");
if (lin_master_transmission_status(&lin_instance)) {
lin_master_send_cmd(&lin_instance,LIN_MASTER_AUTO_TRANSMIT_CMD);
usart_write_wait(&lin_instance,LIN_ID_FIELD_VALUE);
while(1) {
usart_read_buffer_job(&lin_instance,
(uint8_t *)rx_buffer, 5);
}
}
} else {
printf("LIN Works in Slave Mode\r\n");
while(1) {
usart_read_buffer_job(&lin_instance,
(uint8_t *)rx_buffer, 1);
}
}

Workflow

  1. Set up USART LIN module.
    configure_usart_lin();
  2. For LIN master, sending LIN command. For LIN slaver, start reading data .
    if (CONF_LIN_NODE_TYPE == LIN_MASTER_NODE) {
    printf("LIN Works in Master Mode\r\n");
    if (lin_master_transmission_status(&lin_instance)) {
    lin_master_send_cmd(&lin_instance,LIN_MASTER_AUTO_TRANSMIT_CMD);
    usart_write_wait(&lin_instance,LIN_ID_FIELD_VALUE);
    while(1) {
    usart_read_buffer_job(&lin_instance,
    (uint8_t *)rx_buffer, 5);
    }
    }
    } else {
    printf("LIN Works in Slave Mode\r\n");
    while(1) {
    usart_read_buffer_job(&lin_instance,
    (uint8_t *)rx_buffer, 1);
    }
    }