在 Intel® Quark™ 微控制器 D2000 上使用 UART
在 Intel® Quark™ 微控制器 D2000 上使用 UART
获取全新的 Intel® IoT 开发套件,这是一个完整的硬件和软件解决方案,让开发人员能够使用 Intel® Galileo 和 Intel® Edison 主板创建令人兴奋的新解决方案。请访问 Intel® IoT 开发者专区。
目录
- 在 Intel® Quark™ 微控制器 D2000 上使用 UART
- 目录
- 引言
- 必备组件
- Intel® Quark™ 微控制器 D2000 – UART 硬件信息
- UART 功能
- Intel® Quark™ 微控制器开发套件 D2000 详情
- I/O 引脚多路复用
- 在 QMSI 中编程 I/O 引脚多路复用
- UART 时钟门控
- QMSI BSP 中的默认 UART 配置
- 使用 QM_PRINTF 向 UART 写入数据
- 默认 UART
- QM_PRINTF 限制
- 使用 QM_PRINTF 的示例
- 配置 UART 参数
- 读取当前 UART 配置
- 设置新的 UART 配置
- 在
qm_uart_config_t
结构中设置参数 - 配置 UART 示例
- QMSI UART 输入/输出函数
- 获取 UART 状态
- 发送和接收数据
- 阻塞 I/O 函数
- 非阻塞 I/O 函数
- 中断驱动 I/O – 传输结构
- 为中断驱动 I/O 注册中断服务例程
- 中断驱动 I/O 函数
- 直接访问 UART 寄存器
- UART 编程示例:UART 设置和阻塞 I/O
- 描述
- 代码
- UART 编程示例:中断驱动 I/O
- 描述
- 代码
简介
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 代码提供了一个钩子,允许在这种情况下重新编程微控制器。使用以下过程重新编程微控制器
- 暂时将 Intel® Quark™ 微控制器 D2000 引脚 5(封装引脚名称 F_13)连接到地。
- 在 Intel® Quark™ 微控制器开发套件 D2000 上,使用跳线将 Arduino 扩展板引脚 0 – RX 连接到 GND 引脚。
- 重新启动微控制器。
- 在 Intel® Quark™ 微控制器开发套件 D2000 上,只需按下 RESET 按钮。
- 重新启动 OpenOCD。在 Intel® System Studio for Microcontrollers 中,导航到 Debug Perspective,找到 OpenOCD Session 窗口,单击该窗口右上角的红色 Stop OpenOCD 按钮,然后单击绿色 Start OpenOCD 按钮。
- 正常刷新微控制器。
- 断开步骤 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 时钟频率(波特率)。分频器寄存器的值可以计算如下
- 计算分频器,四舍五入到最接近的整数
分频器 = 系统时钟频率 / 波特率 - 计算分频器锁存高位值,四舍五入到最接近的较小或相等整数(向下取整)
dlh = 分频器 / 4096 - 计算分频器锁存低位值,四舍五入到最接近的较小或相等整数(向下取整)
dll = (分频器 - dlh * 4096) / 16 - 计算分频器小数位值:
dlf = 分频器 - dlh * 4096 - dll*16
然后可以使用 QM_UART_CFG_BAUD_DL_PACK(dlh, dll, dlf)
宏获取打包的 baud_divisor
值。
例如,要获得 9600 波特率,并假设系统时钟频率为 32 MHz(如 Intel® Quark™ 微控制器开发套件 D2000 中使用),则使用以下计算
- 分频器 = 32000000 / 9600 = 3333(从 3333.3333 四舍五入)
- dlh = 分频器 / 4096 = 3333 / 4096 = 0
- dll = (分频器 - dlh * 4096) / 16 = (3333 - 0 * 4096) / 16 = 208
- 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 主板上运行此代码
- 打开 Intel® Systems Studio for Microcontrollers。
- 使用 hello_world 作为模板创建新的 QMSI BSP 项目
- 将 main.c 替换为以下代码。
- 编译并将代码刷入微控制器。
- 断开主板与 USB 端口的连接,然后将跳线 J9、J10 和 J11 分别移动到 CTS、TXD 和 N/C 位置。
- 将 FTDI USB TTL 串行电缆 TTL-232R-3V3 电缆连接到 Arduino 扩展板引脚,如下所示
- FTDI 电缆引脚 1 (GND) 连接到 Arduino 扩展板接头上的 GND 引脚
- FTDI 电缆引脚 3 (TX) 连接到 Arduino 扩展板接头上的引脚 0 (RX)
- FTDI 电缆引脚 4 (RX) 连接到 Arduino 扩展板接头上的引脚 1 (TX)
- 重新连接主板到 USB 端口。同时将 FTDI 电缆连接到 USB 端口。
- 在 Windows 操作系统上,您必须将主板的驱动程序更改为 FTDI CDM 驱动程序。
- 在两个 USB 虚拟串行端口上启动终端仿真器软件(例如 PuTTY、screen 或 minicom)。将连接到 FTDI 电缆的端口配置为 115200 bps,将连接到开发套件主板的端口配置为 9600 bps。
- 重置主板。观察两个终端上的登录消息。
- 在一个终端上输入一些字符。输入的字符应该出现在另一个终端上。
- 完成此示例的实验后,使用例如 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 主板上运行此代码
- 打开 Intel® Systems Studio for Microcontrollers。
- 使用 hello_world 作为模板创建新的 QMSI BSP 项目。
- 将 main.c 替换为以下代码。
- 编译并将代码刷入微控制器。
- 将 FTDI USB TTL 串行电缆 TTL-232R-3V3 电缆连接到 Arduino 扩展板引脚,如下所示
- FTDI 电缆引脚 1 (GND) 连接到 Arduino 扩展板接头上的 GND 引脚
- FTDI 电缆引脚 3 (TX) 连接到 Arduino 扩展板接头上的引脚 0 (RX)
- FTDI 电缆引脚 4 (RX) 连接到 Arduino 扩展板接头上的引脚 1 (TX)
- 在 FTDI 电缆串行端口上启动终端仿真器软件(例如 PuTTY、screen 或 minicom)。将连接到 FTDI 电缆的端口配置为 115200 bps。
- 重置主板。观察终端上的消息。
代码
/* 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);
}
}