9. UART LIN

9.1. Overview

The UART LIN component provides LIN protocol functionality based on the UART peripheral. This component supports:

  • Master-slave communication

  • Enhanced checksum mode

  • Both polling and interrupt transfer modes

9.2. Features

  1. Master Mode Features

    • Send/Receive LIN frames

    • Send wakeup signal

    • Support sync interval control

    • Support enhanced checksum

    • Support up to 8 bytes data transfer

  2. Slave Mode Features

    • Respond to master requests

    • Automatic frame header validation

    • Support enhanced checksum

    • Support up to 8 bytes data transfer

  3. Transfer Modes

    • Support polling transfer mode

    • Support interrupt transfer mode

    • Support FIFO trigger level configuration

9.3. Data Structures

9.3.1. Main Structures

  1. uart_lin_master_config_t

    Master configuration structure, containing the following fields:

    • ptr: UART peripheral base address

    • id: LIN frame ID (6 bits)

    • data: LIN data configuration (uart_lin_data_t type)

    • pin_ctrl: Pin control configuration (uart_lin_master_pin_ctrl_t type)

  2. uart_lin_master_pin_ctrl_t

    Master pin control structure, containing the following fields:

    • ptr: GPIO peripheral base address

    • baudrate: LIN baudrate

    • config_uart_pin: UART pin configuration function

    • config_uart_pin_as_gpio: Function to configure UART pin as GPIO

    • delay_us: Microsecond delay function

    • tx_port: Transmit pin port number

    • tx_pin: Transmit pin number

  3. uart_lin_slave_config_t

    Slave configuration structure, containing the following fields:

    • ptr: UART peripheral base address

    • pid: LIN frame protected ID (8 bits)

    • data: LIN data configuration (uart_lin_data_t type)

  4. uart_lin_data_t

    Data transfer configuration structure, containing the following fields:

    • buff: Data buffer pointer

    • length: Data length (maximum 8 bytes)

    • enhance_checksum: Whether to use enhanced checksum

9.4. API Description

9.4.1. Master Mode APIs

  1. Polling Transfer APIs (Blocking)

    • hpm_uart_lin_master_send_frame: Send complete LIN frame * Function: Send sync break, sync field, PID, data, and checksum * Blocks until transmission is complete * Use case: Simple data transmission without interrupt handling

    • hpm_uart_lin_master_receive_frame: Receive complete LIN frame * Function: Send frame header and receive data and checksum * Blocks until reception is complete * Use case: Simple data reception without interrupt handling

  2. Non-blocking Transfer APIs

    • hpm_uart_lin_master_send_head: Send frame header * Function: Send sync break, sync field, and PID * Returns after writing data to FIFO

    • hpm_uart_lin_master_send_data: Send data and checksum * Function: Write data and checksum to UART FIFO * Returns after writing to FIFO * Use case: When transmission complete handling is needed in interrupt

    • hpm_uart_lin_master_receive_data: Receive and verify data * Function: Read data from UART FIFO and verify * Use case: When RX FIFO receives data, trigger interrupt to read and verify data from FIFO

  3. Other Function APIs

    • hpm_uart_lin_send_wakeup: Send wakeup signal (blocking)

    • hpm_uart_lin_calculate_protected_id: Calculate protected ID

9.4.2. Slave Mode APIs

  1. Data Transfer APIs (Non-blocking)

    • hpm_uart_lin_slave_send_data: Send data and checksum * Function: Write data and checksum to UART FIFO * Must be used with UART TX FIFO interrupt * Use case: Send data after detecting master request

    • hpm_uart_lin_slave_receive_data: Receive and verify data * Function: Read data from UART FIFO and verify * Must be used with UART RX timeout interrupt * Use case: Process data after receiving from master

9.5. Usage Examples

9.5.1. Master Mode Examples

  1. Polling Mode Example

/* Configure UART LIN master */
uart_lin_master_config_t uart_lin_config = {
    .ptr = TEST_UART,
    .pin_ctrl = {
        .ptr = HPM_GPIO0,
        .baudrate = TEST_UART_LIN_BAUDRATE,
        .config_uart_pin = init_uart_pins,
        .config_uart_pin_as_gpio = init_uart_pin_as_gpio,
        .delay_us = board_delay_us,
        .tx_port = BOARD_UART_LIN_TX_PORT,
        .tx_pin = BOARD_UART_LIN_TX_PIN,
    },
};

/* Send data (blocking) */
uart_lin_config.id = TEST_MASTER_SEND_ID;
uart_lin_config.data.buff = send_data;
uart_lin_config.data.length = TEST_MASTER_SEND_DATA_LENGTH;
uart_lin_config.data.enhance_checksum = TEST_MASTER_SEND_ENHANCE_CHECKSUM;
hpm_uart_lin_master_send_frame(&uart_lin_config);
  1. Interrupt Mode Example

/* Initiate transfer in main loop */
uart_lin_config.id = TEST_MASTER_SEND_ID;
uart_lin_config.data.buff = send_data;
uart_lin_config.data.length = TEST_MASTER_SEND_DATA_LENGTH;
uart_lin_config.data.enhance_checksum = TEST_MASTER_SEND_ENHANCE_CHECKSUM;
hpm_uart_lin_master_send_head(&uart_lin_config);
hpm_uart_lin_master_send_data(&uart_lin_config);

/* In interrupt handler */
void uart_isr(void)
{
    volatile uint8_t irq_id = uart_get_irq_id(TEST_UART);
    if (irq_id == uart_intr_id_tx_slot_avail) {
        uart_lin_send_complete = true;
        uart_disable_irq(TEST_UART, uart_intr_tx_slot_avail);
    }

    if (irq_id == uart_intr_id_rx_timeout) {
        if (uart_lin_success == hpm_uart_lin_master_receive_data(&uart_lin_config)) {
            uart_lin_receive_complete = true;
        }
        uart_disable_irq(TEST_UART, uart_intr_rx_data_avail_or_timeout);
    }
}

9.5.2. Slave Mode Example

Here’s an example using interrupt mode for receiving and sending data:

/* Configure UART LIN slave */
uart_lin_slave_config_t uart_lin_config = {
    .ptr = TEST_UART,
};

/* Configure UART FIFO control */
uart_fifo_ctrl_t fifo_ctrl = {
    .tx_fifo_level = uart_tx_fifo_trg_not_full,
    .rx_fifo_level = uart_rx_fifo_trg_not_empty,
    .dma_enable = false,
    .fifo_enable = true,
};

/* Process received frame header in interrupt */
void uart_lin_check_head_and_respond(UART_Type *ptr, uint8_t *head_buff)
{
    uint8_t pid = head_buff[1];
    uint8_t id = pid & 0x3f;

    /* Check sync field and PID */
    if (0x55 != head_buff[0] ||
        pid != hpm_uart_lin_calculate_protected_id(id)) {
        return;
    }

    switch (id) {
    case TEST_SLAVE_RECEIVE_ID:
        /* Configure receive parameters */
        uart_lin_config.pid = pid;
        uart_lin_config.data.buff = receive_data;
        uart_lin_config.data.length = TEST_SLAVE_RECEIVE_DATA_LENGTH;
        uart_lin_config.data.enhance_checksum = TEST_SLAVE_RECEIVE_ENHANCE_CHECKSUM;
        break;
    case TEST_SLAVE_SEND_ID:
        /* Configure send parameters and send data */
        uart_lin_config.pid = pid;
        uart_lin_config.data.buff = send_data;
        uart_lin_config.data.length = TEST_SLAVE_SEND_DATA_LENGTH;
        uart_lin_config.data.enhance_checksum = TEST_SLAVE_SEND_ENHANCE_CHECKSUM;
        hpm_uart_lin_slave_send_data(&uart_lin_config);
        uart_enable_irq(ptr, uart_intr_tx_slot_avail);
        break;
    }
}

/* In interrupt handler */
void uart_isr(void)
{
    volatile uint8_t irq_id = uart_get_irq_id(TEST_UART);

    /* Detect LIN break signal */
    if (irq_id == uart_intr_id_rx_line_stat) {
        if (uart_check_status(TEST_UART, uart_stat_line_break)) {
            uart_clear_rx_fifo(TEST_UART);
            head_index = 0;
            uart_config_fifo_ctrl(TEST_UART, &fifo_ctrl);
            uart_enable_irq(TEST_UART, uart_intr_rx_data_avail_or_timeout);
        }
    }

    /* Receive and process frame header */
    if (irq_id == uart_intr_id_rx_data_avail) {
        if (uart_check_status(TEST_UART, uart_stat_data_ready)) {
            head_buff[head_index++] = uart_read_byte(TEST_UART);
        }

        if (head_index == 2) {
            uart_lin_check_head_and_respond(TEST_UART, head_buff);
        }
    }

    /* Handle transmission complete */
    if (irq_id == uart_intr_id_tx_slot_avail) {
        uart_lin_send_complete = true;
        uart_disable_irq(TEST_UART, uart_intr_tx_slot_avail);
    }

    /* Handle reception complete */
    if (irq_id == uart_intr_id_rx_timeout) {
        if (uart_lin_success == hpm_uart_lin_slave_receive_data(&uart_lin_config)) {
            uart_lin_receive_complete = true;
        }
        uart_disable_irq(TEST_UART, uart_intr_rx_data_avail_or_timeout);
    }
}