https://docs.zephyrproject.org/latest/hardware/peripherals/uart.html#uart-interrupt-api
本文基本上就是翻译官方文档,写个笔记
zephyr提供串口的三种方式
1、Polling API(轮询方式)
2、Interrupt-driven API(中断方式)
3、Asynchronous API using Direct Memory Access (DMA)(异步DMA)
配置项
CONFIG_SERIAL
//打开串口驱动,有许多配置项需要依赖这一项
CONFIG_UART_INTERRUPT_DRIVEN
//使能串口中断
CONFIG_UART_ASYNC_API
//使能异步串口中断(DMA)
CONFIG_UART_WIDE_DATA
//使能16字节的api(驱动支持的情况下),比如uart_poll_in_u16、uart_fifo_fill_u16等
CONFIG_UART_USE_RUNTIME_CONFIGURE
//启用UART控制器的运行时配置,允许应用程序在运行时调用uart_configure()来配置UART控制器,并调用uart_config_get()来检索配置
//如果禁用此功能,则UART控制器依赖UART驱动程序的初始化功能来正确配置控制器(dts配置)
CONFIG_UART_LINE_CTRL
//使能流控制
CONFIG_UART_DRV_CMD
//允许使用api向驱动程序发送一些命令
硬件流控制可以参考这位的博客
常用api
此处列举文档中的functions,方便查询,具体参数和返回值详见文档
api | 简述 |
---|---|
int uart_err_check(const struct device *dev) | 检查串口是否错误 |
int uart_configure(const struct device *dev, const struct uart_config *cfg) | 配置串口 |
int uart_config_get(const struct device *dev, struct uart_config *cfg) | 获取当前串口配置 |
int uart_line_ctrl_set(const struct device *dev, uint32_t ctrl, uint32_t val) | 设置串口的流控制(宏控制) |
int uart_line_ctrl_get(const struct device *dev, uint32_t ctrl, uint32_t *val) | 获取串口的流控制等数据 |
int uart_drv_cmd(const struct device *dev, uint32_t cmd, uint32_t p) | 发送额外的命令给驱动(宏控制) |
struct uart_config {
uint32_t baudrate; /* 波特率 */
uint8_t parity; /* 奇偶校验 */
uint8_t stop_bits; /* 停止位 */
uint8_t data_bits; /* 数据位 */
uint8_t flow_ctrl; /* 流控制 */
};
其他函数中所需的结构体详见代码,路径如下:
zephyr/include/zephyr/drivers/uart.h
轮询方式(Polling)
api | 简述 |
---|---|
int uart_poll_in(const struct device *dev, unsigned char *p_char) | 串口接收一个字节的数据 |
int uart_poll_in_u16(const struct device *dev, uint16_t *p_u16) | 接收两个字节的数据(宏配置) |
void uart_poll_out(const struct device *dev, unsigned char out_char) | 串口输出一个字节的数据 |
void uart_poll_out_u16(const struct device *dev, uint16_t out_u16) | 串口输出两个字节数据 |
说明:串口输出直接使用printf puts或printk更便捷
测试demo
/*dts中需要将uart1这个label起个别名*/
aliases {
single-line-uart1 = &usart1;
};
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/devicetree.h>
#include <zephyr/drivers/uart.h>
#define UART_NODE1 DT_ALIAS(single_line_uart1)
const struct device *const sl_uart1 = DEVICE_DT_GET(UART_NODE1);
int main(void)
{
unsigned char recv;
if (!device_is_ready(sl_uart1))
{
printk("uart devices not ready\n");
return 0;
}
while (true)
{
int ret = uart_poll_in(sl_uart1, &recv);
if (ret < 0)
{
printk("Receiving failed. Error: %d\n", ret);
}
else
{
printk("Received %c\n", recv);
}
k_sleep(K_MSEC(1000));
}
return 0;
}
*** Booting Zephyr OS build zephyr-v3.5.0 ***
Receiving failed. Error: -1
Receiving failed. Error: -1
Receiving failed. Error: -1
Received 2
中断方式
函数指针 | 功能 |
---|---|
typedef void (*uart_irq_callback_user_data_t)(const struct device *dev, void *user_data | static inline int uart_irq_callback_set(const struct device *dev, uart_irq_callback_user_data_t cb)的第二个参数,函数指针 |
typedef void (*uart_irq_config_func_t)(const struct device *dev) | 配置串口的函数指针 |
函数 | 简述 |
---|---|
static inline int uart_fifo_fill(const struct device *dev, const uint8_t *tx_data, int size) | 发送8位data到FIFO |
static inline int uart_fifo_fill_u16(const struct device *dev, const uint16_t *tx_data, int size) | 发送16位data到FIFO |
static inline int uart_fifo_read(const struct device *dev, uint8_t *rx_data, const int size) | 从FIFO接收8位 |
static inline int uart_fifo_read_u16(const struct device *dev, uint16_t *rx_data, const int size) | 从FIFO接收16位 |
上述的api,使用的时候,需要先判断 uart_irq_tx_ready() uart_irq_rx_ready(),如果返回1,则必须在中断处理函数中调用
api | brief |
---|---|
void uart_irq_tx_enable(const struct device *dev) | enable TX |
void uart_irq_tx_disable(const struct device *dev) | disable TX |
static inline int uart_irq_tx_ready(const struct device *dev) | 检查发送缓冲区是否有数据 |
void uart_irq_rx_enable(const struct device *dev) | enable RX |
void uart_irq_rx_disable(const struct device *dev) | disable RX |
static inline int uart_irq_tx_complete(const struct device *dev) | 检查tx是否传输完成 |
static inline int uart_irq_rx_ready(const struct device *dev) | 检查接收缓冲区是否有数据 |
void uart_irq_err_enable(const struct device *dev) | enable error interrupt |
void uart_irq_err_disable(const struct device *dev) | Disable error interrupt |
int uart_irq_is_pending(const struct device *dev) | 检查是否有等待的中断 |
int uart_irq_update(const struct device *dev) | 开始中断 |
static inline int uart_irq_callback_user_data_set(const struct device *dev, uart_irq_callback_user_data_t cb, void *user_data) | 设置中断请求函数指针,指定用户uart_irq_callback_user_data_t |
static inline int uart_irq_callback_set(const struct device *dev, uart_irq_callback_user_data_t cb) | 设置中断请求函数指针 |
注:1、中断处理函数中,在调用uart_irq_tx_ready之前,必须调用 uart_irq_update()函数
2、中断处理函数中,在调用uart_irq_tx_complete之前,必须调用 uart_irq_update()函数
3、文档中ISR指Interrupt Service Routine,中断服务程序
4、文档中IRQ指Interrupt Request, 中断请求
5、uart_irq_update函数是中断开始时调用的第一个函数
测试demo可以使用下面的sample,代码中用中断的方式来获取串口接收到的数据,并且判断是否以“\r\n”结尾,如果是,表示一个数据包接收完成,然后将接收到的数据发送到消息队列中,main中的while阻塞等到消息队列是否有数据,如果有,则输出。
/zephyr/samples/drivers/uart/echo_bot/src
dma的方式后续有空再补