554 lines
13 KiB
C
Executable File
554 lines
13 KiB
C
Executable File
// Copyright 2020-2021 Beken
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
#pragma once
|
|
|
|
#include <soc/soc.h>
|
|
#include <driver/hal/hal_uart_types.h>
|
|
#include <driver/hal/hal_gpio_types.h>
|
|
#include "system_hw.h"
|
|
#include "uart_hw.h"
|
|
#include "hal_port.h"
|
|
#include "gpio_map.h"
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
#define UART_LL_REG_BASE(_uart_unit_id) (uart_ll_get_reg_base(_uart_unit_id))
|
|
#define CASE_PARITY(parity) case UART_PARITY_##parity: return UART_V_PARITY_##parity
|
|
#define CASE_D() default: return 0
|
|
|
|
#define UART1_FLOW_CTRL_CNT 0xCC
|
|
|
|
static inline void uart_ll_set_int_enable_status(uart_hw_t *hw, uart_id_t id, uint32_t value)
|
|
{
|
|
hw->int_enable.v = value;
|
|
}
|
|
|
|
static inline void uart_ll_soft_reset(uart_hw_t *hw)
|
|
{
|
|
hw->global_ctrl.soft_reset = 1;
|
|
}
|
|
|
|
static inline uint32_t uart_ll_get_device_id(uart_hw_t *hw)
|
|
{
|
|
return hw->dev_id;
|
|
}
|
|
|
|
static inline uint32_t uart_ll_get_version_id(uart_hw_t *hw)
|
|
{
|
|
return hw->dev_version;
|
|
}
|
|
|
|
static inline uint32_t uart_ll_get_dev_status(uart_hw_t *hw)
|
|
{
|
|
return hw->dev_status;
|
|
}
|
|
|
|
static inline void uart_ll_init(uart_hw_t *hw)
|
|
{
|
|
uart_ll_soft_reset(hw);
|
|
}
|
|
|
|
static inline gpio_id_t uart_ll_get_tx_pin(uart_id_t id)
|
|
{
|
|
switch (id) {
|
|
case UART_ID_0:
|
|
return UART0_TX_PIN;
|
|
case UART_ID_1:
|
|
return UART1_TX_PIN;
|
|
case UART_ID_2:
|
|
return UART2_TX_PIN;
|
|
default:
|
|
return SOC_GPIO_NUM;
|
|
}
|
|
}
|
|
|
|
static inline gpio_id_t uart_ll_get_rx_pin(uart_id_t id)
|
|
{
|
|
switch (id) {
|
|
case UART_ID_0:
|
|
return UART0_RX_PIN;
|
|
case UART_ID_1:
|
|
return UART1_RX_PIN;
|
|
case UART_ID_2:
|
|
return UART2_RX_PIN;
|
|
default:
|
|
return SOC_GPIO_NUM;
|
|
}
|
|
}
|
|
|
|
static inline gpio_id_t uart_ll_get_cts_pin(uart_id_t id)
|
|
{
|
|
switch (id) {
|
|
case UART_ID_0:
|
|
return UART0_CTS_PIN;
|
|
default:
|
|
return SOC_GPIO_NUM;
|
|
}
|
|
}
|
|
|
|
static inline gpio_id_t uart_ll_get_rts_pin(uart_id_t id)
|
|
{
|
|
switch (id) {
|
|
case UART_ID_0:
|
|
return UART0_RTS_PIN;
|
|
default:
|
|
return SOC_GPIO_NUM;
|
|
}
|
|
}
|
|
|
|
static inline uint32_t uart_ll_get_reg_base(uart_id_t id)
|
|
{
|
|
switch (id) {
|
|
case UART_ID_0:
|
|
return UART0_R_BASE;
|
|
case UART_ID_1:
|
|
return UART1_R_BASE;
|
|
case UART_ID_2:
|
|
return UART2_R_BASE;
|
|
default:
|
|
return BK_ERR_UART_BASE;
|
|
}
|
|
}
|
|
|
|
static inline uint32_t uart_ll_to_reg_parity(uart_parity_t parity)
|
|
{
|
|
switch (parity) {
|
|
CASE_PARITY(ODD);
|
|
CASE_PARITY(EVEN);
|
|
CASE_D();
|
|
}
|
|
}
|
|
|
|
static inline bool uart_ll_get_tx_enable(uart_hw_t *hw)
|
|
{
|
|
return hw->config.tx_enable;
|
|
}
|
|
|
|
static inline void uart_ll_set_tx_enable(uart_hw_t *hw, uart_id_t id, uint32_t value)
|
|
{
|
|
hw->config.tx_enable = value & 0x01;
|
|
}
|
|
|
|
static inline void uart_ll_enable_tx(uart_hw_t *hw, uart_id_t id)
|
|
{
|
|
uart_ll_set_tx_enable(hw, id, 1);
|
|
}
|
|
|
|
static inline void uart_ll_disable_tx(uart_hw_t *hw, uart_id_t id)
|
|
{
|
|
uart_ll_set_tx_enable(hw, id, 0);
|
|
}
|
|
|
|
static inline bool uart_ll_get_rx_enable(uart_hw_t *hw)
|
|
{
|
|
return hw->config.rx_enable;
|
|
}
|
|
|
|
static inline void uart_ll_set_rx_enable(uart_hw_t *hw, uart_id_t id, uint32_t value)
|
|
{
|
|
hw->config.rx_enable = value & 0x1;
|
|
}
|
|
|
|
static inline void uart_ll_enable_rx(uart_hw_t *hw, uart_id_t id)
|
|
{
|
|
uart_ll_set_rx_enable(hw, id, 1);
|
|
}
|
|
|
|
#define uart_ll_set_frame_mode(hw, id, mode)
|
|
#define uart_ll_set_mode_uart(hw, id)
|
|
|
|
static inline void uart_ll_disable_rx(uart_hw_t *hw, uart_id_t id)
|
|
{
|
|
uart_ll_set_rx_enable(hw, id, 0);
|
|
}
|
|
|
|
static inline void uart_ll_set_data_bits(uart_hw_t *hw, uart_id_t id, uart_data_bits_t value)
|
|
{
|
|
hw->config.data_bits = value & 0x3;
|
|
}
|
|
|
|
static inline void uart_ll_enable_parity(uart_hw_t *hw, uart_id_t id)
|
|
{
|
|
hw->config.parity_en = 1;
|
|
}
|
|
|
|
static inline void uart_ll_disable_parity(uart_hw_t *hw, uart_id_t id)
|
|
{
|
|
hw->config.parity_en = 0;
|
|
}
|
|
|
|
static inline void uart_ll_set_parity(uart_hw_t *hw, uart_id_t id, uart_parity_t value)
|
|
{
|
|
hw->config.parity = uart_ll_to_reg_parity(value);
|
|
}
|
|
|
|
static inline void uart_ll_set_stop_bits(uart_hw_t *hw, uart_id_t id, uart_stop_bits_t value)
|
|
{
|
|
hw->config.stop_bits = value;
|
|
}
|
|
|
|
static inline void uart_ll_set_clk_div(uart_hw_t *hw, uart_id_t id, uint32_t value)
|
|
{
|
|
hw->config.clk_div = value & UART_F_CLK_DIV_M;
|
|
}
|
|
|
|
static inline void uart_ll_set_tx_fifo_threshold(uart_hw_t *hw, uart_id_t id, uint32_t value)
|
|
{
|
|
hw->fifo_config.tx_fifo_threshold = value & 0xff;
|
|
}
|
|
|
|
static inline void uart_ll_set_rx_fifo_threshold(uart_hw_t *hw, uart_id_t id, uint32_t value)
|
|
{
|
|
hw->fifo_config.rx_fifo_threshold = value & 0xff;
|
|
}
|
|
|
|
static inline void uart_ll_set_rx_stop_detect_time(uart_hw_t *hw, uart_id_t id, uint32_t value)
|
|
{
|
|
hw->fifo_config.rx_stop_detect_time = value & 0x3;
|
|
}
|
|
|
|
static inline void uart_ll_reset_config_to_default(uart_hw_t *hw, uart_id_t id)
|
|
{
|
|
hw->config.v = 0;
|
|
hw->fifo_config.v = 0;
|
|
}
|
|
|
|
static inline uint32_t uart_ll_get_tx_fifo_cnt(uart_hw_t *hw, uart_id_t id)
|
|
{
|
|
return hw->fifo_status.tx_fifo_count;
|
|
}
|
|
|
|
static inline uint32_t uart_ll_get_rx_fifo_cnt(uart_hw_t *hw, uart_id_t id)
|
|
{
|
|
return hw->fifo_status.rx_fifo_count;
|
|
}
|
|
|
|
static inline bool uart_ll_is_tx_fifo_full(uart_hw_t *hw, uart_id_t id)
|
|
{
|
|
return !!(hw->fifo_status.tx_fifo_full);
|
|
}
|
|
|
|
static inline bool uart_ll_is_tx_fifo_empty(uart_hw_t *hw, uart_id_t id)
|
|
{
|
|
return !!(hw->fifo_status.tx_fifo_empty);
|
|
}
|
|
|
|
static inline bool uart_ll_is_rx_fifo_full(uart_hw_t *hw, uart_id_t id)
|
|
{
|
|
return !!(hw->fifo_status.rx_fifo_full);
|
|
}
|
|
|
|
static inline bool uart_ll_is_rx_fifo_empty(uart_hw_t *hw, uart_id_t id)
|
|
{
|
|
return !!(hw->fifo_status.rx_fifo_empty);
|
|
}
|
|
|
|
static inline bool uart_ll_is_fifo_write_ready(uart_hw_t *hw, uart_id_t id)
|
|
{
|
|
return !!(hw->fifo_status.fifo_wr_ready);
|
|
}
|
|
|
|
static inline bool uart_ll_is_fifo_read_ready(uart_hw_t *hw, uart_id_t id)
|
|
{
|
|
return !!(hw->fifo_status.fifo_rd_ready);
|
|
}
|
|
|
|
static inline void uart_ll_reset_fifo_port_to_default(uart_hw_t *hw, uart_id_t id)
|
|
{
|
|
hw->fifo_port.v = 0xffff;
|
|
}
|
|
|
|
static inline void uart_ll_write_byte(uart_hw_t *hw, uart_id_t id, uint8_t data)
|
|
{
|
|
/* note: hw->fifo_port.tx_fifo_data_in = data; is incorrect */
|
|
hw->fifo_port.v = data & 0xff;
|
|
}
|
|
|
|
static inline uint8_t uart_ll_read_byte(uart_hw_t *hw, uart_id_t id)
|
|
{
|
|
return hw->fifo_port.rx_fifo_data_out;
|
|
}
|
|
|
|
static inline uint8_t *uart_ll_get_write_data_addr(uart_hw_t *hw, uart_id_t id)
|
|
{
|
|
return (uint8_t *)(&hw->fifo_port);
|
|
}
|
|
|
|
static inline uint8_t *uart_ll_get_read_data_addr(uart_hw_t *hw, uart_id_t id)
|
|
{
|
|
return (uint8_t *)(((uint32_t)&hw->fifo_port)+1);
|
|
}
|
|
|
|
static inline void uart_ll_reset_int_en_to_default(uart_hw_t *hw, uart_id_t id)
|
|
{
|
|
hw->int_enable.v = 0;
|
|
}
|
|
|
|
static inline void uart_ll_enable_rx_interrupt(uart_hw_t *hw, uart_id_t id)
|
|
{
|
|
hw->int_enable.rx_fifo_need_read = 1;
|
|
hw->int_enable.rx_finish = 1;
|
|
}
|
|
|
|
static inline void uart_ll_disable_rx_interrupt(uart_hw_t *hw, uart_id_t id)
|
|
{
|
|
hw->int_enable.rx_fifo_need_read = 0;
|
|
hw->int_enable.rx_finish = 0;
|
|
}
|
|
|
|
static inline void uart_ll_enable_tx_interrupt(uart_hw_t *hw, uart_id_t id)
|
|
{
|
|
hw->int_enable.tx_fifo_need_write = 1;
|
|
}
|
|
|
|
static inline void uart_ll_disable_tx_interrupt(uart_hw_t *hw, uart_id_t id)
|
|
{
|
|
hw->int_enable.tx_fifo_need_write = 0;
|
|
}
|
|
|
|
static inline void uart_ll_enable_fifo_over_flow_interrupt(uart_hw_t *hw, uart_id_t id)
|
|
{
|
|
hw->int_enable.rx_fifo_overflow = 1;
|
|
}
|
|
|
|
static inline void uart_ll_disable_fifo_over_flow_interrupt(uart_hw_t *hw, uart_id_t id)
|
|
{
|
|
hw->int_enable.rx_fifo_overflow = 0;
|
|
}
|
|
|
|
static inline void uart_ll_enable_parity_err_interrupt(uart_hw_t *hw, uart_id_t id)
|
|
{
|
|
hw->int_enable.rx_parity_err = 1;
|
|
}
|
|
|
|
static inline void uart_ll_disable_parity_err_interrupt(uart_hw_t *hw, uart_id_t id)
|
|
{
|
|
hw->int_enable.rx_parity_err = 0;
|
|
}
|
|
|
|
static inline void uart_ll_enable_stop_bit_err_interrupt(uart_hw_t *hw, uart_id_t id)
|
|
{
|
|
hw->int_enable.rx_stop_bits_err = 1;
|
|
}
|
|
|
|
static inline void uart_ll_disable_stop_bit_err_interrupt(uart_hw_t *hw, uart_id_t id)
|
|
{
|
|
hw->int_enable.rx_stop_bits_err = 0;
|
|
}
|
|
|
|
static inline uint32_t uart_ll_get_int_enable_status(uart_hw_t *hw, uart_id_t id)
|
|
{
|
|
return hw->int_enable.v & 0xff;
|
|
}
|
|
|
|
static inline uint32_t uart_ll_get_interrupt_status(uart_hw_t *hw, uart_id_t id)
|
|
{
|
|
return hw->int_status.v & 0xff;
|
|
}
|
|
|
|
static inline void uart_ll_clear_interrupt_status(uart_hw_t *hw, uart_id_t id, uint32_t status)
|
|
{
|
|
hw->int_status.v = status & 0xff;
|
|
}
|
|
|
|
static inline void uart_ll_clear_id_interrupt_status(uart_hw_t *hw, uart_id_t id)
|
|
{
|
|
hw->int_status.v = 0xff;
|
|
}
|
|
|
|
static inline void uart_ll_clear_id_tx_interrupt_status(uart_hw_t *hw, uart_id_t id)
|
|
{
|
|
/*
|
|
* WARNING:This REG has many bits which attribute is write 1 to clear.
|
|
* If uses union bit operation, the asm codes will read data from REG
|
|
* and write it back, maybe the other bits is 1 and cleared by this function.
|
|
*/
|
|
#if 0
|
|
hw->int_status.tx_fifo_need_write = 1;
|
|
hw->int_status.tx_finish = 1;
|
|
#endif
|
|
//BIT(0):need write, BIT(5): tx finish
|
|
hw->int_status.v = (BIT(0) | BIT(5));
|
|
}
|
|
|
|
static inline void uart_ll_clear_id_rx_interrupt_status(uart_hw_t *hw, uart_id_t id)
|
|
{
|
|
/*
|
|
* WARNING:This REG has many bits which attribute is write 1 to clear.
|
|
* If uses union bit operation, the asm codes will read data from REG
|
|
* and write it back, maybe the other bits is 1 and cleared by this function.
|
|
*/
|
|
#if 0
|
|
hw->int_status.rx_fifo_need_read = 1;
|
|
hw->int_status.rx_finish = 1;
|
|
#endif
|
|
//BIT(1):need read, BIT(6): rx finish
|
|
hw->int_status.v = (BIT(1) | BIT(6));
|
|
}
|
|
|
|
static inline bool uart_ll_is_rx_interrupt_triggered(uart_hw_t *hw, uart_id_t id, uint32_t status)
|
|
{
|
|
return !!(status & (BIT(1) | BIT(6)));
|
|
}
|
|
|
|
static inline bool uart_ll_is_rx_recv_fini_int_triggered(uart_hw_t *hw, uart_id_t id, uint32_t status)
|
|
{
|
|
return !!(status & BIT(6));
|
|
}
|
|
|
|
static inline bool uart_ll_is_tx_interrupt_triggered(uart_hw_t *hw, uart_id_t id, uint32_t status)
|
|
{
|
|
return !!(status & BIT(0));
|
|
}
|
|
|
|
static inline bool uart_ll_is_rx_over_flow_int_triggered(uart_hw_t *hw, uart_id_t id, uint32_t status)
|
|
{
|
|
return !!(status & BIT(2));
|
|
}
|
|
|
|
static inline bool uart_ll_is_rx_parity_err_int_triggered(uart_hw_t *hw, uart_id_t id, uint32_t status)
|
|
{
|
|
return !!(status & BIT(3));
|
|
}
|
|
|
|
static inline bool uart_ll_is_rx_stop_bits_err_int_triggered(uart_hw_t *hw, uart_id_t id, uint32_t status)
|
|
{
|
|
return !!(status & BIT(4));
|
|
}
|
|
|
|
static inline void uart_ll_reset_flow_control_to_default(uart_hw_t *hw, uart_id_t id)
|
|
{
|
|
hw->flow_ctrl_config.v = 0;
|
|
}
|
|
|
|
static inline void uart_ll_enable_flow_control(uart_hw_t *hw, uart_id_t id)
|
|
{
|
|
hw->flow_ctrl_config.flow_ctrl_en = 1;
|
|
}
|
|
|
|
static inline void uart_ll_disable_flow_control(uart_hw_t *hw, uart_id_t id)
|
|
{
|
|
hw->flow_ctrl_config.flow_ctrl_en = 0;
|
|
}
|
|
|
|
static inline bool uart_ll_is_flow_control_enabled(uart_hw_t *hw, uart_id_t id)
|
|
{
|
|
return !!(hw->flow_ctrl_config.flow_ctrl_en);
|
|
}
|
|
|
|
static inline void uart_ll_set_flow_control_low_cnt(uart_hw_t *hw, uart_id_t id, uint32_t cnt)
|
|
{
|
|
hw->flow_ctrl_config.flow_ctrl_low_cnt = cnt & 0xff;
|
|
}
|
|
|
|
static inline void uart_ll_set_flow_control_high_cnt(uart_hw_t *hw, uart_id_t id, uint32_t cnt)
|
|
{
|
|
hw->flow_ctrl_config.flow_ctrl_high_cnt = cnt & 0xff;
|
|
}
|
|
|
|
static inline void uart_ll_set_rts_polarity(uart_hw_t *hw, uart_id_t id, uint32_t value)
|
|
{
|
|
hw->flow_ctrl_config.rts_polarity_sel = value & 0x1;
|
|
}
|
|
|
|
static inline void uart_ll_set_cts_polarity(uart_hw_t *hw, uart_id_t id, uint32_t value)
|
|
{
|
|
hw->flow_ctrl_config.cts_polarity_sel = value & 0x1;
|
|
}
|
|
|
|
static inline void uart_ll_reset_wake_config_to_default(uart_hw_t *hw, uart_id_t id)
|
|
{
|
|
hw->wake_config.v = 0;
|
|
}
|
|
|
|
#if CONFIG_UART_PM_CB_SUPPORT
|
|
#define UART_PM_BACKUP_REG_NUM (6)
|
|
|
|
static inline void uart_ll_backup(uart_hw_t *hw, uint32_t *pm_backup)
|
|
{
|
|
pm_backup[0] = hw->config.v;
|
|
pm_backup[1] = hw->fifo_config.v;
|
|
pm_backup[2] = hw->int_enable.v;
|
|
pm_backup[3] = hw->flow_ctrl_config.v;
|
|
pm_backup[4] = hw->wake_config.v;
|
|
pm_backup[5] = hw->global_ctrl.v;
|
|
}
|
|
|
|
static inline void uart_ll_restore(uart_hw_t *hw, uint32_t *pm_backup)
|
|
{
|
|
hw->config.v = pm_backup[0];
|
|
hw->fifo_config.v = pm_backup[1];
|
|
hw->int_enable.v = pm_backup[2];
|
|
hw->flow_ctrl_config.v = pm_backup[3];
|
|
hw->wake_config.v = pm_backup[4];
|
|
hw->global_ctrl.v = pm_backup[5];
|
|
}
|
|
#endif
|
|
|
|
#if CONFIG_ENABLE_FILTER_GLITCH
|
|
static inline void uart_ll_set_glitch_width(uart_hw_t *hw, uint32_t width)
|
|
{
|
|
hw->glitch_cancel_config.glitch_width = width & 0x7fff;
|
|
}
|
|
|
|
static inline uint32_t uart_ll_get_glitch_width(uart_hw_t *hw)
|
|
{
|
|
return hw->glitch_cancel_config.glitch_width;
|
|
}
|
|
|
|
static inline void uart_ll_enable_glitch_cancel(uart_hw_t *hw)
|
|
{
|
|
hw->glitch_cancel_config.cancel_en = 1;
|
|
}
|
|
|
|
static inline void uart_ll_disable_glitch_cancel(uart_hw_t *hw)
|
|
{
|
|
hw->glitch_cancel_config.cancel_en = 0;
|
|
}
|
|
#endif // CONFIG_ENABLE_FILTER_GLITCH
|
|
|
|
static inline uint32_t uart_ll_wait_tx_over(void)
|
|
{
|
|
uint32_t uart_wait_us;
|
|
uint32_t baudrate0;
|
|
uint32_t baudrate1;
|
|
uint32_t baudrate2;
|
|
|
|
uart_hw_t *hw0 = (uart_hw_t *)UART_LL_REG_BASE(0);
|
|
uart_hw_t *hw1 = (uart_hw_t *)UART_LL_REG_BASE(1);
|
|
uart_hw_t *hw2 = (uart_hw_t *)UART_LL_REG_BASE(2);
|
|
|
|
baudrate0 = UART_CLOCK / (hw0->config.clk_div + 1);
|
|
baudrate1 = UART_CLOCK / (hw1->config.clk_div + 1);
|
|
baudrate2 = UART_CLOCK / (hw2->config.clk_div + 1);
|
|
|
|
uart_wait_us = 1000000 * hw2->fifo_status.tx_fifo_count * 10 / baudrate2
|
|
+ 1000000 * hw1->fifo_status.tx_fifo_count * 10 / baudrate1
|
|
+ 1000000 * hw0->fifo_status.tx_fifo_count * 10 / baudrate0;
|
|
|
|
while (!hw2->fifo_status.tx_fifo_empty);
|
|
while (!hw1->fifo_status.tx_fifo_empty);
|
|
while (!hw0->fifo_status.tx_fifo_empty);
|
|
|
|
return uart_wait_us;
|
|
}
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|