65.9K
CodeProject 正在变化。 阅读更多。
Home

在 Intel® Quark™ 微控制器 D2000 上使用 UART

starIconstarIconstarIconstarIconstarIcon

5.00/5 (1投票)

2016年9月8日

CPOL

19分钟阅读

viewsIcon

20365

在 Intel® Quark™ 微控制器 D2000 上使用 UART

获取全新的 Intel® IoT 开发套件,这是一个完整的硬件和软件解决方案,让开发人员能够使用 Intel® Galileo 和 Intel® Edison 主板创建令人兴奋的新解决方案。请访问 Intel® IoT 开发者专区

目录

简介

Intel® Quark™ 微控制器 D2000 具有两个 UART 接口。本文档描述了如何使用 Intel® Quark™ 微控制器软件接口 (QMSI) 对这些 UART 接口进行编程。

先决条件

本文档假设读者熟悉 Intel® System Studio for Microcontrollers 套件——一个用于开发、优化和调试 Intel® Quark™ 微控制器应用程序的集成工具集。Intel® System Studio for Microcontrollers 可在此处下载:https://software.intel.com/en-us/intel-system-studio-microcontrollers(请务必选择 D2000 作为目标)。有关设置和使用 Intel® System Studio for Microcontrollers 的更多信息,请参阅 Intel® System Studio 2016 for Microcontrollers 入门指南

本文档以 Intel® Quark™ 微控制器开发套件 D2000 主板为参考,但本文档中的信息可应用于任何基于 Intel® Quark™ 微控制器 D2000 的项目。

本文档讨论了与 UART 编程相关的 Intel® Quark™ 微控制器软件接口 (QMSI) 函数。它不提供完整的 QMSI 文档。有关更多信息,请参阅 Intel® Quark™ 微控制器软件接口 指南。

Intel® Quark™ 微控制器 D2000 – UART 硬件信息

UART 功能

Intel® Quark™ 微控制器 D2000 中集成的 UART 接口与 16550 标准软件兼容。每个 UART 都有 16 字节的 TX 和 RX FIFO,支持 5 到 9 位数据格式,波特率从 300 bps 到 2 Mbps。提供 CTS/RTS 硬件流控制。还支持 RS485 模式。

有关 UART 功能的更多信息,请参阅 Intel® Quark™ 微控制器 D2000 数据手册第 14 节“UART”。

Intel® Quark™ 微控制器开发套件 D2000 详情

在 Intel® Quark™ 微控制器开发套件 D2000 主板上,UART 接口信号连接如下

  • UART_A RXD 和 TXD 信号分别在 Arduino 扩展板的引脚 0 和 1 上可用。这些引脚在下图中标记为 (1)。
  • UART_A RST 和 CTS 信号分别在 Arduino 扩展板的引脚 A2 和 A3 上可用。
  • UART_B 信号连接到 FTDI TTL-232R-3V3 兼容的接头 J2。此接头在下图中标记为 (3)。这些信号也可以通过使用下图中标记为 (2) 的跳线组连接到板载 USB 转 UART/JTAG FT232H 接口 IC。
    • 通过将跳线 J9、J10 和 J11 分别设置为 CTS、TXD 和 N/C 位置,UART 信号可以连接到板载 FT232H IC。
    • 当使用连接到 J2 接头的 FTDI 电缆时,需要通过移除跳线 J15 – RTS/TMS、J17 – RXD/TCK 并将跳线 J11 移动到 N/C 位置来断开 UART 信号与板载 FT232H IC 的连接。
    • 要在 JTAG 模式下使用板载 FT232H IC,跳线 J9、J10 和 J11 需要分别设置为 TDO、TDI 和 TRST 位置,并且跳线 J15 和 J17 需要连接。

I/O 引脚多路复用

为了在有限的 I/O 引脚数量下启用多个接口,Intel® Quark™ 微控制器 D2000 对 I/O 引脚的功能进行多路复用。每个 I/O 引脚最多可分配 3 种不同的功能之一。

默认情况下,只有第一个 UART 接口 (UART_A) 的 RXD 信号被多路复用到一个 I/O 引脚。第二个 UART 接口 (UART_B) 信号默认不连接到 I/O 引脚——这些引脚用于 JTAG 接口。下表列出了与 UART 接口及其功能相关的 I/O 引脚。

MCU 引脚编号和名称 QMSI 引脚名称 功能 0 功能 1 功能 2 开发套件 D2000 - Arduino 扩展板引脚名称

4 – F_12

QM_PIN_ID_12

GPIO12

AI12

UART_A_TXD*

1

5 – F_13

QM_PIN_ID_13

GPIO13*

AI13

UART_A_RXD

0

6 – F_14

QM_PIN_ID_14

GPIO14*

AI14

UART_A_RTS / UART_A_DE

A2

7 – F_15

QM_PIN_ID_15

GPIO15*

AI15

UART_A_CTS / UART_A_RE

A3

13 – F_20

QM_PIN_ID_20

TRST_N*

GPIO20

UART_B_TXD

UART_B 接头 – 引脚 5

USB – FT232H (J11)

14 – F_21

QM_PIN_ID_21

TCK*

GPIO21

UART_B_RXD

UART_B 接头 – 引脚 4

USB – FT232H (J17)

15 – F_22

QM_PIN_ID_22

TMS*

GPIO22

UART_B_RTS / UART_B_DE

UART_B 接头 – 引脚 2

USB – FT232H (J15)

16 – F_23

QM_PIN_ID_23

TDI*

GPIO23

UART_B_CTS / UART_B_RE

UART_B 接头 – 引脚 6

USB – FT232H (J9)

*默认模式

在 QMSI 中编程 I/O 引脚多路复用

QMSI 提供以下函数来设置引脚多路复用

qm_rc_t qm_pmux_select(qm_pin_id_t pin, qm_pmux_fn_t fn)

qm_pmux_select 函数将 pin 参数指定的 I/O 引脚设置为 fn 参数指定的功能。例如,以下调用在引脚 QM_PIN_ID_13 上选择功能 2 (UART_A_RXD)

qm_pmux_select(QM_PIN_ID_13, QM_PMUX_FN_2);

qm_rc_t qm_pmux_input_en(qm_pin_id_t pin, bool enable)

qm_pmux_input_en 函数根据 enable 参数的值,启用或禁用 pin 参数指定的 I/O 引脚上的输入模式。例如,以下调用在引脚 QM_PIN_ID_13 上启用输入模式

qm_pmux_input_en(QM_PIN_ID_13, true);

配置 UART_A 引脚多路复用的代码片段

qm_pmux_select(QM_PIN_ID_12, QM_PMUX_FN_2);

qm_pmux_select(QM_PIN_ID_13, QM_PMUX_FN_2);

qm_pmux_input_en(QM_PIN_ID_13, true);

/* Following 3 calls only needed when using RTS/CTS handshake */

qm_pmux_select(QM_PIN_ID_14, QM_PMUX_FN_2);

qm_pmux_select(QM_PIN_ID_15, QM_PMUX_FN_2);

qm_pmux_input_en(QM_PIN_ID_14, true);

配置 UART_B 引脚多路复用的代码片段

qm_pmux_select(QM_PIN_ID_20, QM_PMUX_FN_2);

qm_pmux_select(QM_PIN_ID_21, QM_PMUX_FN_2);

qm_pmux_input_en(QM_PIN_ID_21, true);

/* Following 3 calls only needed when using RTS/CTS handshake */

qm_pmux_select(QM_PIN_ID_22, QM_PMUX_FN_2);

qm_pmux_select(QM_PIN_ID_23, QM_PMUX_FN_2);

qm_pmux_input_en(QM_PIN_ID_22, true);

重要提示

一旦 UART_B 信号多路复用到 I/O 引脚,JTAG 功能将不再可用,并且微控制器无法使用 JTAG 接口进行控制(刷新或调试)。引导 ROM 代码提供了一个钩子,允许在这种情况下重新编程微控制器。使用以下过程重新编程微控制器

  1. 暂时将 Intel® Quark™ 微控制器 D2000 引脚 5(封装引脚名称 F_13)连接到地。
    • 在 Intel® Quark™ 微控制器开发套件 D2000 上,使用跳线将 Arduino 扩展板引脚 0 – RX 连接到 GND 引脚。
  2. 重新启动微控制器。
    • 在 Intel® Quark™ 微控制器开发套件 D2000 上,只需按下 RESET 按钮。
  3. 重新启动 OpenOCD。在 Intel® System Studio for Microcontrollers 中,导航到 Debug Perspective,找到 OpenOCD Session 窗口,单击该窗口右上角的红色 Stop OpenOCD 按钮,然后单击绿色 Start OpenOCD 按钮。
  4. 正常刷新微控制器。
  5. 断开步骤 1 中连接的引脚(否则固件将无法运行)。

UART 时钟门控

为了降低功耗,Intel® Quark™ 微控制器 D2000 允许启用或禁用片上外设(包括 UART 接口)的时钟。可以使用 clk_periph_enable QMSI 函数如下启用 UART 接口的时钟

/* enable clock for UART_A */

clk_periph_enable(CLK_PERIPH_CLK | CLK_PERIPH_UARTA_REGISTER);

/* enable clock for UART_B */

clk_periph_enable(CLK_PERIPH_CLK | CLK_PERIPH_UARTB_REGISTER);

QMSI BSP 中的默认 UART 配置

默认情况下,QMSI BSP(板级支持包)将 UART_A 配置如下

  • 只有 TX 信号多路复用到 I/O 引脚(仅输出)
  • 波特率设置为 115000 bps
  • UART 数据格式配置为 8 数据位、无奇偶校验和 1 停止位

以下 QMSI BSP 函数处理 UART 设置

  • sys/app_entry.c 中的 _start()
  • sys/newlib-syscalls.c 中的 stdout_uart_setup()

使用 QM_PRINTF 向 UART 写入数据

QMSI 提供 QM_PRINTF 函数——C 标准库 printf 函数的简化版本,可用于向 UART 输出数据。

默认 UART

默认情况下,QM_PRINTF 函数使用 UART_A 进行输出。这是通过 include/qm_common.h 中的 STDOUT_UART 宏定义的。要将 UART_B 用于 QM_PRINTF 输出,请将 STDOUT_UART_1 定义为 1。这应该在 #include <qm_common.h> 指令之前完成。例如

#define STDOUT_UART_1 (1)
#include <qm_common.h>

QM_PRINTF 限制

由于代码大小限制,QM_PRINTF 仅支持 printf 格式说明符的子集

  • 支持以下格式说明符
    • %d – 有符号整数;忽略长“l”子说明符
    • %u – 无符号整数;忽略长“l”子说明符
    • %X%x – 十六进制格式的整数
    • %s – 字符串
  • 不支持填充。%02d 之类的格式说明符将导致不正确的输出。
  • 不支持字符格式说明符 %c

使用 QM_PRINTF 的示例

以下代码将在默认 UART 上打印一条消息。

QM_PRINTF("Welcome to Intel Quark Microcontroller D2000\r\n");

配置 UART 参数

读取当前 UART 配置

QMSI 使用 qm_uart_config_t 结构来存储 UART 配置。可以使用 qm_uart_get_config 函数读取当前 UART 配置

qm_rc_t qm_uart_get_config(const qm_uart_t uart, qm_uart_config_t *cfg)

uart 参数指定 UART 接口:QM_UART_0 用于 UART_A,QM_UART_1 用于 UARTB_B。cfg 参数指定用于存储配置数据的 qm_uart_config_t 结构的位置。例如,以下代码将读取 UART_A 的配置。

qm_uart_config_t uart0_cfg;
qm_uart_get_config(QM_UART_0, &uart0_cfg);

设置新的 UART 配置

可以使用 qm_uart_set_config 函数设置新的 UART 配置

qm_rc_t qm_uart_set_config(const qm_uart_t uart, const qm_uart_config_t *cfg)

uart 参数指定 UART 接口,cfg 参数指定包含新配置参数的 qm_uart_config_t 结构的位置。

qm_uart_config_t 结构中设置参数

qm_uart_config_t 包含以下成员

line_control

line_control 变量包含 UART 线路控制寄存器 (LCR) 的设置。此寄存器配置 UART 数据格式:数据位数、停止位数和奇偶校验设置。include/qm_uart.h 文件提供了常用 LCR 值的定义

/**
 * UART Line control.
 */
typedef enum {
	QM_UART_LC_5N1 = 0x00,   /**< 5 data bits, no parity, 1 stop bit */
	QM_UART_LC_5N1_5 = 0x04, /**< 5 data bits, no parity, 1.5 stop bits */
	QM_UART_LC_5E1 = 0x18,   /**< 5 data bits, even parity, 1 stop bit */
	QM_UART_LC_5E1_5 = 0x1c, /**< 5 data bits, even parity, 1.5 stop bits */
	QM_UART_LC_5O1 = 0x08,   /**< 5 data bits, odd parity, 1 stop bit */
	QM_UART_LC_5O1_5 = 0x0c, /**< 5 data bits, odd parity, 1.5 stop bits */
	QM_UART_LC_6N1 = 0x01,   /**< 6 data bits, no parity, 1 stop bit */
	QM_UART_LC_6N2 = 0x05,   /**< 6 data bits, no parity, 2 stop bits */
	QM_UART_LC_6E1 = 0x19,   /**< 6 data bits, even parity, 1 stop bit */
	QM_UART_LC_6E2 = 0x1d,   /**< 6 data bits, even parity, 2 stop bits */
	QM_UART_LC_6O1 = 0x09,   /**< 6 data bits, odd parity, 1 stop bit */
	QM_UART_LC_6O2 = 0x0d,   /**< 6 data bits, odd parity, 2 stop bits */
	QM_UART_LC_7N1 = 0x02,   /**< 7 data bits, no parity, 1 stop bit */
	QM_UART_LC_7N2 = 0x06,   /**< 7 data bits, no parity, 2 stop bits */
	QM_UART_LC_7E1 = 0x1a,   /**< 7 data bits, even parity, 1 stop bit */
	QM_UART_LC_7E2 = 0x1e,   /**< 7 data bits, even parity, 2 stop bits */
	QM_UART_LC_7O1 = 0x0a,   /**< 7 data bits, odd parity, 1 stop bit */
	QM_UART_LC_7O2 = 0x0e,   /**< 7 data bits, odd parity, 2 stop bits */
	QM_UART_LC_8N1 = 0x03,   /**< 8 data bits, no parity, 1 stop bit */
	QM_UART_LC_8N2 = 0x07,   /**< 8 data bits, no parity, 2 stop bits */
	QM_UART_LC_8E1 = 0x1b,   /**< 8 data bits, even parity, 1 stop bit */
	QM_UART_LC_8E2 = 0x1f,   /**< 8 data bits, even parity, 2 stop bits */
	QM_UART_LC_8O1 = 0x0b,   /**< 8 data bits, odd parity, 1 stop bit */
	QM_UART_LC_8O2 = 0x0f    /**< 8 data bits, odd parity, 2 stop bits */
} qm_uart_lc_t;

baud_divisor

baud_divisor 变量配置 UART 波特率。它包含 UART 分频器寄存器的打包设置。每个 UART 有三个分频器寄存器

  • DLH - 分频器锁存高位 - 8 位大小
  • DLL - 分频器锁存低位 - 8 位大小
  • DLF - 分频器锁存小数位 - 4 位大小

这些分频器寄存器定义了系统时钟频率需要除以多少才能获得 UART 时钟频率(波特率)。分频器寄存器的值可以计算如下

  1. 计算分频器,四舍五入到最接近的整数
    分频器 = 系统时钟频率 / 波特率
  2. 计算分频器锁存高位值,四舍五入到最接近的较小或相等整数(向下取整)
    dlh = 分频器 / 4096
  3. 计算分频器锁存低位值,四舍五入到最接近的较小或相等整数(向下取整)
    dll = (分频器 - dlh * 4096) / 16
  4. 计算分频器小数位值:
    dlf = 分频器 - dlh * 4096 - dll*16

然后可以使用 QM_UART_CFG_BAUD_DL_PACK(dlh, dll, dlf) 宏获取打包的 baud_divisor 值。

例如,要获得 9600 波特率,并假设系统时钟频率为 32 MHz(如 Intel® Quark™ 微控制器开发套件 D2000 中使用),则使用以下计算

  1. 分频器 = 32000000 / 9600 = 3333(从 3333.3333 四舍五入)
  2. dlh = 分频器 / 4096 = 3333 / 4096 = 0
  3. dll = (分频器 - dlh * 4096) / 16 = (3333 - 0 * 4096) / 16 = 208
  4. dlf = 分频器 - dlh * 4096 - dll * 16 = 3333 - 0 * 4096 - 208 * 16 = 5

下表给出了常用波特率的分频器值,假设系统时钟为 32 MHz

波特率 dlh(分频器锁存高位) dll(分频器锁存低位) dlf(分频器锁存小数位)

115200 bps

0

17

6

57600 bps

0

34

12

38400 bps

0

52

1

19200 bps

0

104

3

9600 bps

0

208

5

2400 bps

3

65

5

1200 bps

6

130

11

hw_fc

hw_fc 是一个布尔变量,用于启用或禁用硬件流控制。将其设置为 0 禁用硬件流控制,将其设置为 1 启用硬件流控制。

配置 UART 示例

以下代码片段将 UART_A 配置为 9600 bps、8 数据位、无奇偶校验、1 停止位、无硬件流控制。分频器值的计算如上文 baud_divisor 部分所述。

qm_uart_config_t uart0_cfg;

uart0_cfg.baud_divisor = QM_UART_CFG_BAUD_DL_PACK(0, 208, 5);

uart0_cfg.line_control = QM_UART_LC_8N1;

uart0_cfg.hw_fc = 0;

qm_uart_set_config(QM_UART_0, &uart0_cfg);

QMSI UART 输入/输出函数

获取 UART 状态

QMSI 提供 qm_uart_get_status 函数来获取 UART 的当前状态。

qm_uart_status_t qm_uart_get_status(const qm_uart_t uart)

uart 参数指定要获取状态的 UART。

返回值是一个或多个以下值的按位或

  • QM_UART_IDLE – UART TX FIFO 和发送移位寄存器为空。
  • QM_UART_LSR_OE – 接收器溢出错误
  • QM_UART_LSR_PE – 接收器奇偶校验错误
  • QM_UART_LSR_FE – 接收器帧错误
  • QM_UART_LSR_BI – “中断”条件
  • QM_UART_TX_BUSY – UART TX FIFO 或发送移位寄存器不为空
  • QM_UART_RX_BUSY – 接收数据已准备就绪

发送和接收数据

QMSI 提供了几个功能略有不同的函数来发送和接收数据。它们可以分为以下几类

  • 阻塞 I/O – 这些函数等待数据发送或接收。
  • 非阻塞 I/O – 这些函数立即返回。这些函数不检查错误、数据可用性或 TX FIFO 中的空间。调用者应使用 qm_uart_get_status 函数检查这些条件。
  • 中断驱动 I/O – 这些函数在后台发送或接收数据,使用 UART 中断管理发送和接收 FIFO。

阻塞 I/O 函数

qm_rc_t qm_uart_write(const qm_uart_t uart, const uint8_t data)

qm_uart_write 函数将 data 参数指定的单个字节数据写入 uart 参数指定的 UART。这是一个阻塞 I/O 函数,它将等待(不返回)直到数据发送完毕。目前,qm_uart_write 函数始终返回 QM_RC_OK 值。

qm_uart_status_t qm_uart_read(const qm_uart_t uart, uint8_t *data)

qm_uart_read 函数从 uart 参数指定的 UART 读取单个字节数据。它将数据存储在 data 指针指定的位置。这是一个阻塞 I/O 函数,它将等待(不返回)直到数据可用并可以读取,或者发生错误。此函数的返回值是一个或多个以下值的按位或

  • QM_UART_OK – 数据读取成功
  • QM_UART_LSR_OE – 接收器溢出错误
  • QM_UART_LSR_PE – 接收器奇偶校验错误
  • QM_UART_LSR_FE – 接收器帧错误
  • QM_UART_LSR_BI – “中断”条件

qm_rc_t qm_uart_write_buffer(const qm_uart_t uart, const uint8_t *const data, uint32_t len)

qm_uart_write_buffer 函数是一个阻塞 I/O 函数。它从 data 参数指定的缓冲区写入多个字节。要写入的字节数由 len 参数指定。目前,qm_uart_write_buffer 函数始终返回 QM_RC_OK 值。

非阻塞 I/O 函数

qm_rc_t qm_uart_write_non_block(const qm_uart_t uart, const uint8_t data)

qm_uart_write_non_block 函数将 data 参数指定的单个字节数据写入 uart 参数指定的 UART。这是一个非阻塞 I/O 函数。它将在将数据写入 UART 的发送保持寄存器后立即返回。它不检查 TX FIFO 中是否有可用空间。目前,qm_uart_write_non_block 函数始终返回 QM_RC_OK 值。

uint8_t qm_uart_read_non_block(const qm_uart_t uart)

qm_uart_read_non_block 函数从 uart 参数指定的 UART 读取并返回单个字节数据。这是一个非阻塞 I/O 函数。此函数立即返回,不检查是否接收到数据,或是否发生任何接收错误。返回值是 UART 接收缓冲寄存器的内容。

中断驱动 I/O – 传输结构

中断驱动 I/O 函数使用 qm_uart_transfer_t 结构传递数据传输的参数。此结构包含以下成员

data

data 变量是一个 uint8_t* 指针,指向缓冲区。对于写入函数,缓冲区应包含要发送的数据。对于读取函数,它指定存储接收数据的缓冲区。

data_len

data_len 变量是一个 uint32_t 值,指定要传输的字节数。

fin_callback

fin_callback 变量包含指向数据传输完成后要调用的回调函数的指针。应用程序必须定义此回调(err_callback 不能为 NULL 值)。

回调函数的签名是 void fin_callback(uint32_t id, uint32_t len),其中 id 参数指定传输标识符(参见下面的 id 变量),len 参数指定成功传输的字节数。

err_callback

err_callback 变量包含指向在发生接收错误时要调用的回调函数的指针。目前,它不用于写入操作。应用程序必须为读取或写入操作定义此回调(err_callback 不能为 NULL 值)。

此回调函数的签名是 void err_callback(uint32_t id, qm_uart_status_t status),其中 id 参数指定传输标识符(参见下面的 id 变量),status 参数包含线路状态寄存器 (LSR) 中的错误位——一个或多个以下值的按位或

  • QM_UART_LSR_OE – 接收器溢出错误
  • QM_UART_LSR_PE – 接收器奇偶校验错误
  • QM_UART_LSR_FE – 接收器帧错误
  • QM_UART_LSR_BI – “中断”条件

id

id 参数是一个 uint32_t 传输标识符。应用程序可以使用此参数在回调函数中识别传输。请注意,QMSI 每个 UART 仅支持一个活动读取和一个活动写入传输。

为中断驱动 I/O 注册中断服务例程

在使用中断驱动 I/O 函数之前,需要注册 QMSI UART 中断服务例程 (ISR)。这通过调用 qm_irq_request 函数并使用以下参数来完成

  • 对于 UART_A
    qm_irq_request(QM_IRQ_UART_0, qm_uart_0_isr);
  • 对于 UART_B
    qm_irq_request(QM_IRQ_UART_1, qm_uart_1_isr);

中断驱动 I/O 函数

qm_uart_status_t qm_uart_irq_write(const qm_uart_t uart, const qm_uart_transfer_t *const xfer)

qm_uart_irq_write 函数启动中断驱动的 UART 写入传输。uart 参数指定用于写入传输的 UART。xfer 参数指定填充了数据位置、长度、回调函数指针和传输 ID 的传输结构的位置。

函数返回以下值之一

  • QM_UART_OK – 传输成功启动
  • QM_UART_TX_BUSY – UART TX FIFO 或 UART 发送保持寄存器繁忙。在这种情况下不启动传输。

qm_uart_status_t qm_uart_irq_read(const qm_uart_t uart, const qm_uart_transfer_t *const xfer)

qm_uart_irq_read 函数启动中断驱动的 UART 读取传输。uart 参数指定用于读取传输的 UART。xfer 参数指定填充了数据位置、长度、回调函数指针和传输 ID 的传输结构的位置。

函数返回以下值之一

  • QM_UART_OK – 传输成功启动
  • QM_UART_RX_BUSY – 上次传输尚未完成。上次请求中指定的数据长度尚未读取。在这种情况下不启动传输。

qm_rc_t qm_uart_write_terminate(const qm_uart_t uart)

qm_uart_write_terminate 函数终止 uart 参数指定的 UART 的当前中断驱动写入传输。它调用传输完成回调函数,指示实际写入的字节数。目前,qm_uart_write_terminate 始终返回 QM_RC_OK

qm_rc_t qm_uart_read_terminate(const qm_uart_t uart)

qm_uart_read_terminate 函数终止 uart 参数指定的 UART 的当前中断驱动读取传输。它调用传输完成回调函数,指示实际读取的字节数。目前,qm_uart_read_terminate 函数始终返回 QM_RC_OK 值。

直接访问 UART 寄存器

要访问 QMSI UART 输入/输出函数未公开的 UART 功能,您可以直接访问 UART 寄存器。Intel® Quark™ 微控制器 D2000 中的 UART 寄存器是内存映射的,并通过 QM_UART 数组向 QMSI 程序员公开,该数组包含每个 UART 的 qm_uart_reg_t 结构。qm_uart_reg_t 结构包含所有 UART 寄存器。例如,要访问 UART_A 的调制解调器控制寄存器 (MCR) 并设置回环位,可以使用以下代码

QM_UART[QM_UART_0].mcr |= BIT(4);

请参阅 qm_soc_regs.h 获取 qm_uart_reg_t 结构的定义,并参阅 Intel® Quark™ 微控制器 D2000 数据手册 获取有关 UART 寄存器的信息。

UART 编程示例:UART 设置和阻塞 I/O

描述

以下代码展示了如何配置和使用两个 UART 接口。它将 UART_A 配置为 115200 bps,将 UART_B 配置为 9600 bps。接下来,它扫描两个 UART 接口以查找可用数据。当 UART 上有字符可用时,它会被读取并写入另一个 UART。

按照以下步骤在 Intel® Quark™ 微控制器开发套件 D2000 主板上运行此代码

  1. 打开 Intel® Systems Studio for Microcontrollers。
  2. 使用 hello_world 作为模板创建新的 QMSI BSP 项目
  3. main.c 替换为以下代码。
  4. 编译并将代码刷入微控制器。
  5. 断开主板与 USB 端口的连接,然后将跳线 J9、J10 和 J11 分别移动到 CTS、TXD 和 N/C 位置。
  6. 将 FTDI USB TTL 串行电缆 TTL-232R-3V3 电缆连接到 Arduino 扩展板引脚,如下所示
    • FTDI 电缆引脚 1 (GND) 连接到 Arduino 扩展板接头上的 GND 引脚
    • FTDI 电缆引脚 3 (TX) 连接到 Arduino 扩展板接头上的引脚 0 (RX)
    • FTDI 电缆引脚 4 (RX) 连接到 Arduino 扩展板接头上的引脚 1 (TX)
  7. 重新连接主板到 USB 端口。同时将 FTDI 电缆连接到 USB 端口。
    • 在 Windows 操作系统上,您必须将主板的驱动程序更改为 FTDI CDM 驱动程序。
  8. 在两个 USB 虚拟串行端口上启动终端仿真器软件(例如 PuTTY、screen 或 minicom)。将连接到 FTDI 电缆的端口配置为 115200 bps,将连接到开发套件主板的端口配置为 9600 bps。
  9. 重置主板。观察两个终端上的登录消息。
  10. 在一个终端上输入一些字符。输入的字符应该出现在另一个终端上。
  11. 完成此示例的实验后,使用例如 hello_world 代码重新编程主板,如 I/O 引脚多路复用部分中的重要说明所述。
    • 在 Windows 操作系统上,您必须将主板的驱动程序更改为 WinUSB 驱动程序。

代码

/* UART configuration example */

#include <qm_common.h>
#include <qm_pinmux.h>
#include <qm_uart.h>
#include <qm_scss.h>

int main(void)
{
	qm_uart_config_t uart0_cfg;
	qm_uart_config_t uart1_cfg;
	uint8_t uart0_message[] =
	    "This is UART_A. Characters typed here will appear on UART_B.\r\n";
	uint8_t uart1_message[] =
	    "This is UART_B. Characters typed here will appear on UART_A.\r\n";
	uint8_t data;

	/* UART_A I/O pins multiplexing setup
	 * QMSI BSP only configures UART_A_TXD signal.
	 * The following code configures both TXD and RXD signals
	 * and sets up RXD pin in input mode
	 */
	qm_pmux_select(QM_PIN_ID_12, QM_PMUX_FN_2); /* configure UART_A_TXD */
	qm_pmux_select(QM_PIN_ID_13, QM_PMUX_FN_2); /* configure UART_A_RXD */
	qm_pmux_input_en(QM_PIN_ID_13, true); /* UART_A_RXD is an input */
	
	/* UART_B I/O pins multiplexing setup
	 * By default UART_B pins are multiplexed to JTAG.
	 * The following code configures all relevant pins to UART_B signals
       * and sets up RXD and RTS pins in input mode
	 */
	qm_pmux_select(QM_PIN_ID_20, QM_PMUX_FN_2); /* configure UART_B_TXD */
	qm_pmux_select(QM_PIN_ID_21, QM_PMUX_FN_2); /* configure UART_B_RXD */
	qm_pmux_select(QM_PIN_ID_22, QM_PMUX_FN_2); /* configure UART_B_RTS */
	qm_pmux_select(QM_PIN_ID_23, QM_PMUX_FN_2); /* configure UART_B_CTS */
	qm_pmux_input_en(QM_PIN_ID_21, true); /* UART_B_RXD is an input */
	qm_pmux_input_en(QM_PIN_ID_22, true); /* UART_B_RTS is an input */

	/* Stores current UART_A configuration to uart0_cfg */
	qm_uart_get_config(QM_UART_0, &uart0_cfg);

	/* Configures UART_A for 115200 bps */
	uart0_cfg.baud_divisor = QM_UART_CFG_BAUD_DL_PACK(0, 17, 6);

	/* Configures UART_B for 9600 bps,
	 * 8 data bits, no parity, 1 stop bit
	 */
	uart1_cfg.baud_divisor = QM_UART_CFG_BAUD_DL_PACK(0, 208, 5);
	uart1_cfg.line_control = QM_UART_LC_8N1;
	uart1_cfg.hw_fc = 1;

	qm_uart_set_config(QM_UART_0, &uart0_cfg);
	qm_uart_set_config(QM_UART_1, &uart1_cfg);

	/* enable clock for UART_A */
	clk_periph_enable(CLK_PERIPH_CLK | CLK_PERIPH_UARTA_REGISTER);
	/* enable clock for UART_B */
	clk_periph_enable(CLK_PERIPH_CLK | CLK_PERIPH_UARTB_REGISTER);

	/* this message will only be printed on the default UART */
	QM_PRINTF("Welcome to Intel Quark D2000 UART configuration demo.\r\n");

	qm_uart_write_buffer(QM_UART_0, uart0_message, sizeof(uart0_message));
	qm_uart_write_buffer(QM_UART_1, uart1_message, sizeof(uart1_message));

	while(1) {
		/* checks if received data is available on UART_A */
		if (qm_uart_get_status(QM_UART_0) && QM_UART_RX_BUSY) {
			/* reads byte from UART_A */
			if (qm_uart_read(QM_UART_0, &data) == QM_UART_OK) {
				/* and sends to to UART_B */
				qm_uart_write(QM_UART_1, data);
				/* adds line feed in case of carriage return */
				if (data == '\r') {
					qm_uart_write(QM_UART_1, '\n');
				}
			}
		}
		/* checks if received data is available on UART_B */
		if (qm_uart_get_status(QM_UART_1) && QM_UART_RX_BUSY) {
			/* reads byte from UART_B */
			if (qm_uart_read(QM_UART_1, &data) == QM_UART_OK) {
				/* and sends to to UART_A */
				qm_uart_write(QM_UART_0, data);
				/* adds line feed in case of carriage return */
				if (data == '\r') {
					qm_uart_write(QM_UART_0, '\n');
				}
			}
		}
	}

	return 0;
}

UART 编程示例:中断驱动 I/O

描述

以下代码展示了如何使用中断驱动 I/O。它将 UART_A 配置为 115200 bps,并打印登录消息。接下来,它将 UART 配置为回环模式,设置并启动中断驱动的发送操作,然后设置并启动中断驱动的接收操作。当两个操作都完成后,它禁用回环模式并打印接收到的数据。

按照以下步骤在 Intel® Quark™ 微控制器开发套件 D2000 主板上运行此代码

  1. 打开 Intel® Systems Studio for Microcontrollers。
  2. 使用 hello_world 作为模板创建新的 QMSI BSP 项目。
  3. main.c 替换为以下代码。
  4. 编译并将代码刷入微控制器。
  5. 将 FTDI USB TTL 串行电缆 TTL-232R-3V3 电缆连接到 Arduino 扩展板引脚,如下所示
    • FTDI 电缆引脚 1 (GND) 连接到 Arduino 扩展板接头上的 GND 引脚
    • FTDI 电缆引脚 3 (TX) 连接到 Arduino 扩展板接头上的引脚 0 (RX)
    • FTDI 电缆引脚 4 (RX) 连接到 Arduino 扩展板接头上的引脚 1 (TX)
  6. 在 FTDI 电缆串行端口上启动终端仿真器软件(例如 PuTTY、screen 或 minicom)。将连接到 FTDI 电缆的端口配置为 115200 bps。
  7. 重置主板。观察终端上的消息。

代码

/* UART interrupt driven I/O example */

#include <qm_pinmux.h>
#include <qm_uart.h>
#include <qm_interrupt.h>
#include <qm_scss.h>
#include <qm_power.h>

#define TX_XFER_ID 1
#define RX_XFER_ID 2

static void uart0_tx_callback(uint32_t id, uint32_t len);
static void uart0_rx_callback(uint32_t id, uint32_t len);
static void uart0_error_callback(uint32_t id, qm_uart_status_t status);
void uart_set_loopback_mode(const qm_uart_t uart, bool enable);

static uint8_t tx_buffer[] =
		"This is the test data being send and received by the UART.";
static uint8_t rx_buffer[64];

static bool tx_xfer_complete = false;
static bool rx_xfer_complete = false;
static bool rx_xfer_error = 0;

int main(void)
{
	qm_uart_config_t uart0_cfg;
	qm_uart_transfer_t tx_xfer, rx_xfer;

	/* Configures UART_A for 115200 bps */
	uart0_cfg.baud_divisor = QM_UART_CFG_BAUD_DL_PACK(0, 17, 6);
	uart0_cfg.line_control = QM_UART_LC_8N1;
	uart0_cfg.hw_fc = false;

	/* Multiplexes the UARTA RXD and RXD pins and enables input for RXD */
	qm_pmux_select(QM_PIN_ID_12, QM_PMUX_FN_2);
	qm_pmux_select(QM_PIN_ID_13, QM_PMUX_FN_2);
	qm_pmux_input_en(QM_PIN_ID_13, true);

	clk_periph_enable(CLK_PERIPH_CLK | CLK_PERIPH_UARTA_REGISTER);
	qm_uart_set_config(QM_UART_0, &uart0_cfg);

	QM_PRINTF("Welcome to Intel Quark D2000 UART interrupt driven I/O demo.\r\n");

	/* Enables UART loopback mode */
	uart_set_loopback_mode(QM_UART_0, true);

	/* Sets up interrupt service routine for UART_A */
	qm_irq_request(QM_IRQ_UART_0, qm_uart_0_isr);

	/* Sets up interrupt driven transmit request */
	tx_xfer.data = tx_buffer;
	tx_xfer.data_len = sizeof(tx_buffer);
	tx_xfer.fin_callback = uart0_tx_callback;
	tx_xfer.err_callback = uart0_error_callback;
	tx_xfer.id = TX_XFER_ID;

	/* Initiates interrupt driven transmit request */
	qm_uart_irq_write(QM_UART_0, &tx_xfer);

	/* Sets up interrupt driven receive request */
	rx_xfer.data = rx_buffer;
	rx_xfer.data_len = sizeof(tx_buffer);
	rx_xfer.fin_callback = uart0_rx_callback;
	rx_xfer.err_callback = uart0_error_callback;
	rx_xfer.id = RX_XFER_ID;

	/* Initiates interrupt driven receive request */
	qm_uart_irq_read(QM_UART_0, &rx_xfer);


	/* Waits for transfers to complete */
	while (!tx_xfer_complete || !rx_xfer_complete) {
		cpu_halt();
	}

	/* Disables UART loopback mode */
	uart_set_loopback_mode(QM_UART_0, false);

	if (0 == rx_xfer_error) {
		QM_PRINTF("UART interrupt driven transmit and receive complete.\r\n");
		QM_PRINTF("Buffer: %s\r\n", rx_buffer);
	} else {
		QM_PRINTF("UART interrupt driven I/O error.\r\n");
		QM_PRINTF("UART LSR error bits: 0x%d\r\n", rx_xfer_error);
	}

	while(1) {
		cpu_halt();
	}

	return 0;
}

void uart0_tx_callback(uint32_t id, uint32_t len)
{
	switch (id) {

	case TX_XFER_ID:
		tx_xfer_complete = true;
		break;

	default:
		break;
	}
}

void uart0_rx_callback(uint32_t id, uint32_t len)
{
	switch (id) {

	case RX_XFER_ID:
		rx_xfer_complete = true;
		break;
	default:
		break;
	}
}

void uart0_error_callback(uint32_t id, qm_uart_status_t status)
{
	rx_xfer_error = status;
}

void uart_set_loopback_mode(const qm_uart_t uart, bool enable)
{
	if (enable) {
		QM_UART[uart].mcr |= BIT(4);
	} else {
		QM_UART[uart].mcr &= ~BIT(4);
	}
}
© . All rights reserved.