赞
踩
在介绍完GPIO的相关内容下一个必须介绍的就是uart了,因为串口一个主要用途就是用于调试信息打印。
HPM6750在uart的配置上也是相当炸裂,有17个串口;结合HPM6750的高主频高内存,完全可以作为一个串口服务器。
TX FIFO 包含待发送的数据,并将数据传送到 TX 移位寄存器。TX 移位寄存器为并行-串行转换器,把发送数据转换成串行的比特流。
TXFIFO 的写入口是THR寄存器 (Transmitter Holding Register)。用户需要把FCR寄存器 (FIFO Control Reg- ister) 的 FIFOE 位置 1,来打开 TXFIFO。
RX 控制器使用波特率控制模块生成的过采样时钟,对输入的每一位进行采样,并把收到的每一位移入 RX 移 位寄存器。RX 移位寄存器对数据进行串行-并行转换,并把数据存入 RX FIFO。RX FIFO 的读入口是RBR寄存器 (Receiver Buffer Register),用户需要把FCR寄存器 (FIFO Control Register)的 FIFOE 位置 1,来打开 RXFIFO。
在时钟章节我们讲到每个外设都可以八选一选择一个功能时钟,并且设置分频。
上图中我们通过clock_set_source_divider设置uart0选择clk_src_osc24m=24MHz时钟源,不分频,也就是说上图中的配置uart0输入时钟为24MHz。
UART 时钟与波特率的比率就是过采样率OSC。
RX 控制器利用过采样时钟对输入数据进行采样。假设过采样率OSC为 16 当检测到输入信号第一个下降沿 时 (起始 START 位),计数器从 1 开始计数直到 16,在计数到 8 时,RX 控制器对输入数据采样。计数器在计数 到 16 后,会复位到 1,以此采样下一位数据,循环往复,直到停止 STOP 位。TX 控制器同样利用过采样时钟来 生成输出数据流。
uart外设内部还有一个时钟分频寄存器(16位)Divisor。分频值的 MSB 位于DLM寄存器 (Divisor Latch MSB),而 LSB 位于DLL寄存器 (Divisor Latch LSB)。
三者之间的关系如下:
在SDK中有一个函数专门用于计算分频系数和过采样率,对于开发者来讲,只需要设置输入时钟和波特率即可。
由于uart0使用PY06/07作为TXD/RXD, 而PY06/07属于电源管理域的引脚,所以必须先通过HPM_PIOC先将引脚映射到HPM_IOC中,然后由HPM_IOC再将PY06/07复用为外设引脚。
- typedef struct hpm_uart_config {
- uint32_t src_freq_in_hz; /**< Source clock frequency in Hz */
- uint32_t baudrate; /**< Baudrate */
- uint8_t num_of_stop_bits; /**< Number of stop bits */
- uint8_t word_length; /**< Word length */
- uint8_t parity; /**< Parity */
- uint8_t tx_fifo_level; /**< TX Fifo level */
- uint8_t rx_fifo_level; /**< RX Fifo level */
- bool dma_enable; /**< DMA Enable flag */
- bool fifo_enable; /**< Fifo Enable flag */
- uart_modem_config_t modem_config; /**< Modem config */
- #if defined(UART_SOC_HAS_RXLINE_IDLE_DETECTION) && (UART_SOC_HAS_RXLINE_IDLE_DETECTION == 1)
- uart_rxline_idle_config_t rxidle_config; /**< RX Idle configuration */
- #endif
- #if defined(UART_SOC_HAS_TXLINE_IDLE_DETECTION) && (UART_SOC_HAS_TXLINE_IDLE_DETECTION == 1)
- uart_rxline_idle_config_t txidle_config; /**< TX Idle configuration */
- #endif
- #if defined(UART_SOC_HAS_RXEN_CFG) && (UART_SOC_HAS_RXEN_CFG == 1)
- bool rx_enable; /**< RX Enable configuration */
- #endif
- } uart_config_t;
各个字段含义:
src_freq_in_hz | 输入时钟,八选一,并且可以分频(注意uart内部可以再次分频) |
baudrate | 波特率 |
num_of_stop_bits | 停止位 typedef enum num_of_stop_bits { |
word_length | 字长 typedef enum word_length { |
parity | 奇偶校验位 typedef enum parity { |
tx_fifo_level | 发送触发阈值 |
rx_fifo_level | 接收触发阈值 |
dma_enable | 使能DMA |
fifo_enable | 使能FIFO |
modem_config | 流控 typedef struct uart_modem_config { |
uart_init函数用于设置波特率、字长、停止位、奇偶校验以及FIFO阈值。
- hpm_stat_t uart_init(UART_Type *ptr, uart_config_t *config)
- {
- uint32_t tmp;
- uint8_t osc;
- uint16_t div;
-
- /* disable all interrupts */
- ptr->IER = 0;
- /* Set DLAB to 1 */
- ptr->LCR |= UART_LCR_DLAB_MASK;
-
- if (!uart_calculate_baudrate(config->src_freq_in_hz, config->baudrate, &div, &osc)) {
- return status_uart_no_suitable_baudrate_parameter_found;
- }
- ptr->OSCR = (ptr->OSCR & ~UART_OSCR_OSC_MASK)
- | UART_OSCR_OSC_SET(osc);
- ptr->DLL = UART_DLL_DLL_SET(div >> 0);
- ptr->DLM = UART_DLM_DLM_SET(div >> 8);
-
- //设置奇偶校验
- /* DLAB bit needs to be cleared once baudrate is configured */
- tmp = ptr->LCR & (~UART_LCR_DLAB_MASK);
-
- tmp &= ~(UART_LCR_SPS_MASK | UART_LCR_EPS_MASK | UART_LCR_PEN_MASK);
- switch (config->parity) {
- case parity_none:
- break;
- case parity_odd:
- tmp |= UART_LCR_PEN_MASK;
- break;
- case parity_even:
- tmp |= UART_LCR_PEN_MASK | UART_LCR_EPS_MASK;
- break;
- case parity_always_1:
- tmp |= UART_LCR_PEN_MASK | UART_LCR_SPS_MASK;
- break;
- case parity_always_0:
- tmp |= UART_LCR_EPS_MASK | UART_LCR_PEN_MASK
- | UART_LCR_SPS_MASK;
- break;
- default:
- /* invalid configuration */
- return status_invalid_argument;
- }
- //设置停止位
- tmp &= ~(UART_LCR_STB_MASK | UART_LCR_WLS_MASK);
- switch (config->num_of_stop_bits) {
- case stop_bits_1:
- break;
- case stop_bits_1_5:
- tmp |= UART_LCR_STB_MASK;
- break;
- case stop_bits_2:
- if (config->word_length < word_length_6_bits) {
- /* invalid configuration */
- return status_invalid_argument;
- }
- tmp |= UART_LCR_STB_MASK;
- break;
- default:
- /* invalid configuration */
- return status_invalid_argument;
- }
- //设置字长
- ptr->LCR = tmp | UART_LCR_WLS_SET(config->word_length);
-
- //复位FIFO并设置FIFO阈值
-
- #if defined(UART_SOC_HAS_FINE_FIFO_THR) && (UART_SOC_HAS_FINE_FIFO_THR == 1)
- /* reset TX and RX fifo */
- ptr->FCRR = UART_FCRR_TFIFORST_MASK | UART_FCRR_RFIFORST_MASK;
- /* Enable FIFO */
- ptr->FCRR = UART_FCRR_FIFOT4EN_MASK
- | UART_FCRR_FIFOE_SET(config->fifo_enable)
- | UART_FCRR_TFIFOT4_SET(config->tx_fifo_level)
- | UART_FCRR_RFIFOT4_SET(config->rx_fifo_level)
- | UART_FCRR_DMAE_SET(config->dma_enable);
-
- #else
- /* reset TX and RX fifo */
- ptr->FCR = UART_FCR_TFIFORST_MASK | UART_FCR_RFIFORST_MASK;
- /* Enable FIFO */
- tmp = UART_FCR_FIFOE_SET(config->fifo_enable)
- | UART_FCR_TFIFOT_SET(config->tx_fifo_level)
- | UART_FCR_RFIFOT_SET(config->rx_fifo_level)
- | UART_FCR_DMAE_SET(config->dma_enable);
- ptr->FCR = tmp;
- /* store FCR register value */
- ptr->GPR = tmp;
- #endif
-
- uart_modem_config(ptr, &config->modem_config);
-
- #if defined(UART_SOC_HAS_RXLINE_IDLE_DETECTION) && (UART_SOC_HAS_RXLINE_IDLE_DETECTION == 1)
- uart_init_rxline_idle_detection(ptr, config->rxidle_config);
- #endif
- #if defined(UART_SOC_HAS_RXEN_CFG) && (UART_SOC_HAS_RXEN_CFG == 1)
- if (config->rx_enable) {
- ptr->IDLE_CFG |= UART_IDLE_CFG_RXEN_MASK;
- }
- #endif
- return status_success;
- }
读取字节
-
- hpm_stat_t uart_receive_byte(UART_Type *ptr, uint8_t *byte)
- {
- uint32_t retry = 0;
-
- while (!(ptr->LSR & UART_LSR_DR_MASK)) {
- if (retry > HPM_UART_DRV_RETRY_COUNT) {
- break;
- }
- retry++;
- }
-
- if (retry > HPM_UART_DRV_RETRY_COUNT) {
- return status_timeout;
- }
-
- *byte = ptr->RBR & UART_RBR_RBR_MASK;
- return status_success;
- }
不断查询LSR寄存器的UART_LSR_DR_MASK是否置位(存在有效的接收数据时该位置 1),如果置位说明可读,此时RBR寄存器存储的就是当前可读字节。
写入字节
- hpm_stat_t uart_send_byte(UART_Type *ptr, uint8_t c)
- {
- uint32_t retry = 0;
-
- while (!(ptr->LSR & UART_LSR_THRE_MASK)) {
- if (retry > HPM_UART_DRV_RETRY_COUNT) {
- break;
- }
- retry++;
- }
-
- if (retry > HPM_UART_DRV_RETRY_COUNT) {
- return status_timeout;
- }
-
- ptr->THR = UART_THR_THR_SET(c);
- return status_success;
- }
不断查询LSR寄存器的UART_LSR_THRE_MASK是否置位(发送FIFO空),如果置位说明可写,此时写入THR寄存器就会传送给TX FIFO。
VScode打开工程并进入调试窗口,在
- cd ~/workspace/work/hpm/hello_world
- code .
以上就是uart的基本内容,包括功能说明、引脚配置、时钟配置、轮询读写。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。