串口通信是嵌入式开发中最常用的外设之一,无论是单片机开发还是嵌入式 Linux 开发,串口都扮演着重要角色。通过串口,我们可以将开发板与电脑连接,使用串口调试助手调试程序,或者与蓝牙、GPS、GPRS 等模块进行通信。在嵌入式 Linux 中,串口通常被用作控制台,因此掌握串口的使用是嵌入式开发的必备技能。

本文将详细介绍 i.MX6ULL 的串口通信机制,包括 UART 的基本原理、硬件配置、寄存器操作以及驱动开发。


1. UART 通信简介

1.1 什么是 UART?

UART(Universal Asynchronous Receiver/Transmitter,通用异步收发传输器)是一种异步串行通信协议。它通过两根信号线(TX 和 RX)实现全双工通信,适用于短距离、低速率的通信场景。

1.2 UART 通信格式

UART 通信的数据帧格式如下:

空闲位 | 起始位 | 数据位(5-8位) | 校验位(可选) | 停止位(1-2位) | 空闲位
   1   |    0   |   D0 D1 D2 D3 D4 D5 D6 D7  |   P   |    1   |    1
  • 空闲位:数据线在空闲状态时为高电平(逻辑“1”)。
  • 起始位:数据线从高电平变为低电平(逻辑“0”),表示数据传输开始。
  • 数据位:实际传输的数据,通常为 8 位。
  • 校验位:用于错误检测(奇校验或偶校验)。
  • 停止位:数据线恢复为高电平(逻辑“1”),表示数据传输结束。

1.3 UART 电平标准

  • TTL 电平:低电平表示逻辑“0”,高电平表示逻辑“1”。
  • RS-232 电平:-3V 到 -15V 表示逻辑“1”,+3V 到 +15V 表示逻辑“0”。

2. i.MX6ULL 的 UART 硬件

i.MX6ULL 集成了 8 个 UART 控制器,每个 UART 控制器支持以下特性:

  • 最高波特率:5 Mbps。
  • 支持 9 位或多节点模式(RS-485)。
  • 可编程的奇偶校验(奇校验或偶校验)。
  • 自动波特率检测(最高支持 115.2 Kbps)。

2.1 UART 时钟源

UART 的时钟源由寄存器 CCM_CSCDR1UART_CLK_SEL 位选择:

  • 0:选择 pll3_80m(80 MHz)。
  • 1:选择 osc_clk(24 MHz)。

通常选择 pll3_80m 作为时钟源,并通过 UART_CLK_PODF 位设置分频值(1~64 分频)。


3. UART 寄存器配置

3.1 重要寄存器

以下是 UART 控制器的主要寄存器:

寄存器名称功能描述
UARTx_UCR1控制寄存器 1,用于使能 UART 和自动波特率检测。
UARTx_UCR2控制寄存器 2,用于配置数据位、停止位、校验位等。
UARTx_UCR3控制寄存器 3,用于配置接收多路选择器。
UARTx_USR2状态寄存器 2,用于检测发送和接收状态。
UARTx_UFCRFIFO 控制寄存器,用于设置参考时钟分频。
UARTx_UBIR波特率整数寄存器,用于设置波特率。
UARTx_UBMR波特率小数寄存器,用于设置波特率。
UARTx_URXD接收数据寄存器,用于读取接收到的数据。
UARTx_UTXD发送数据寄存器,用于写入要发送的数据。

3.2 波特率计算

波特率的计算公式如下:
[
\text{Baud Rate} = \frac{\text{Ref Freq}}{16 \times (\text{UBMR} + 1) / (\text{UBIR} + 1)}
]
其中:

  • Ref Freq:参考时钟频率(如 80 MHz)。
  • UBMR:波特率小数寄存器的值。
  • UBIR:波特率整数寄存器的值。

例如,设置波特率为 115200:

  • Ref Freq = 80 MHz
  • UBIR = 71
  • UBMR = 3124

4. UART 驱动开发

4.1 初始化 UART

以下是 UART 初始化的代码示例:

#include <stdint.h>

#define UART1_BASE_ADDR 0x02020000  // UART1 基地址
#define UART1_UCR1      (*(volatile uint32_t *)(UART1_BASE_ADDR + 0x80))
#define UART1_UCR2      (*(volatile uint32_t *)(UART1_BASE_ADDR + 0x84))
#define UART1_UFCR      (*(volatile uint32_t *)(UART1_BASE_ADDR + 0x90))
#define UART1_UBIR      (*(volatile uint32_t *)(UART1_BASE_ADDR + 0xA4))
#define UART1_UBMR      (*(volatile uint32_t *)(UART1_BASE_ADDR + 0xA8))
#define UART1_URXD      (*(volatile uint32_t *)(UART1_BASE_ADDR + 0x00))
#define UART1_UTXD      (*(volatile uint32_t *)(UART1_BASE_ADDR + 0x40))

void uart_init(uint32_t baud_rate) {
    // 设置波特率
    uint32_t uart_clk = 80000000;  // 80 MHz
    uint32_t baud_div = uart_clk / baud_rate;
    UART1_UBIR = (baud_div >> 4) & 0xFFFF;
    UART1_UBMR = baud_div & 0xF;

    // 配置数据格式:8 位数据,1 位停止位,无校验
    UART1_UCR2 |= (1 << 5) | (1 << 2) | (1 << 1);

    // 使能 UART
    UART1_UCR1 |= (1 << 0);
}

4.2 发送数据

通过 UARTx_UTXD 寄存器发送数据:

void uart_send_char(char c) {
    while (!(UART1_UCR2 & (1 << 3)));  // 等待发送缓冲区为空
    UART1_UTXD = c;
}

void uart_send_string(const char *str) {
    while (*str) {
        uart_send_char(*str++);
    }
}

4.3 接收数据

通过 UARTx_URXD 寄存器接收数据:

char uart_receive_char() {
    while (!(UART1_UCR2 & (1 << 0)));  // 等待接收数据
    return UART1_URXD & 0xFF;
}

void uart_receive_string(char *buffer, uint32_t length) {
    for (uint32_t i = 0; i < length; i++) {
        buffer[i] = uart_receive_char();
        if (buffer[i] == '\n' || buffer[i] == '\r') {
            buffer[i] = '\0';
            break;
        }
    }
}

5. 总结

通过本文,我们详细介绍了 i.MX6ULL 的串口通信机制,包括 UART 的基本原理、硬件配置、寄存器操作以及驱动开发。以下是关键点总结:

  • UART 通信格式:包括空闲位、起始位、数据位、校验位和停止位。
  • UART 寄存器:通过配置寄存器实现波特率设置、数据格式配置和数据收发。
  • 驱动开发:通过初始化、发送和接收函数实现串口通信。