Skip to content

RT-Thread 驱动开发

RT-Thread 设备驱动框架

RT-Thread 提供了完整的设备驱动框架,应用层通过统一的 I/O 设备管理接口访问硬件:

应用层
  rt_device_find("uart1")
  rt_device_open() / rt_device_read() / rt_device_write()


I/O 设备管理层(rt_device_t)


设备驱动层(rt_device_ops)


硬件抽象层(HAL)

注册设备驱动

c
/* uart_drv.c */
#include <rtthread.h>
#include <rtdevice.h>

struct my_uart_device {
    struct rt_device    parent;    /* 必须是第一个成员 */
    rt_uint32_t         base_addr;
    rt_uint32_t         irq_num;
    struct rt_semaphore rx_sem;
    struct rt_ringbuffer *rx_rb;
};

/* 实现设备操作接口 */
static rt_err_t my_uart_init(rt_device_t dev)
{
    struct my_uart_device *uart = (struct my_uart_device *)dev;
    /* 初始化硬件 */
    hw_uart_init(uart->base_addr, 115200);
    rt_sem_init(&uart->rx_sem, "uart_rx", 0, RT_IPC_FLAG_FIFO);
    uart->rx_rb = rt_ringbuffer_create(256);
    return RT_EOK;
}

static rt_err_t my_uart_open(rt_device_t dev, rt_uint16_t oflag)
{
    struct my_uart_device *uart = (struct my_uart_device *)dev;
    /* 使能中断 */
    rt_hw_interrupt_install(uart->irq_num, my_uart_isr, uart, "uart");
    rt_hw_interrupt_umask(uart->irq_num);
    return RT_EOK;
}

static rt_err_t my_uart_close(rt_device_t dev)
{
    struct my_uart_device *uart = (struct my_uart_device *)dev;
    rt_hw_interrupt_mask(uart->irq_num);
    return RT_EOK;
}

static rt_ssize_t my_uart_read(rt_device_t dev, rt_off_t pos,
                                void *buffer, rt_size_t size)
{
    struct my_uart_device *uart = (struct my_uart_device *)dev;
    rt_uint8_t *buf = (rt_uint8_t *)buffer;
    rt_size_t received = 0;

    while (received < size) {
        /* 等待数据 */
        if (rt_sem_take(&uart->rx_sem, RT_WAITING_FOREVER) != RT_EOK)
            break;

        rt_size_t n = rt_ringbuffer_get(uart->rx_rb,
                                         buf + received, size - received);
        received += n;
    }
    return received;
}

static rt_ssize_t my_uart_write(rt_device_t dev, rt_off_t pos,
                                 const void *buffer, rt_size_t size)
{
    struct my_uart_device *uart = (struct my_uart_device *)dev;
    const rt_uint8_t *buf = (const rt_uint8_t *)buffer;

    for (rt_size_t i = 0; i < size; i++) {
        /* 等待发送缓冲区空 */
        while (!hw_uart_tx_ready(uart->base_addr))
            ;
        hw_uart_write_byte(uart->base_addr, buf[i]);
    }
    return size;
}

static rt_err_t my_uart_control(rt_device_t dev, int cmd, void *args)
{
    struct my_uart_device *uart = (struct my_uart_device *)dev;

    switch (cmd) {
    case RT_DEVICE_CTRL_CONFIG: {
        struct serial_configure *cfg = (struct serial_configure *)args;
        hw_uart_set_baud(uart->base_addr, cfg->baud_rate);
        return RT_EOK;
    }
    default:
        return -RT_EINVAL;
    }
}

/* 设备操作接口表 */
#ifdef RT_USING_DEVICE_OPS
static const struct rt_device_ops my_uart_ops = {
    .init    = my_uart_init,
    .open    = my_uart_open,
    .close   = my_uart_close,
    .read    = my_uart_read,
    .write   = my_uart_write,
    .control = my_uart_control,
};
#endif

/* 中断处理 */
static void my_uart_isr(int irqno, void *param)
{
    struct my_uart_device *uart = (struct my_uart_device *)param;
    rt_uint8_t byte;

    while (hw_uart_rx_ready(uart->base_addr)) {
        byte = hw_uart_read_byte(uart->base_addr);
        rt_ringbuffer_putchar(uart->rx_rb, byte);
    }

    /* 通知读取任务 */
    rt_sem_release(&uart->rx_sem);
}

/* 注册设备 */
static struct my_uart_device uart1_dev = {
    .base_addr = UART1_BASE,
    .irq_num   = UART1_IRQ,
};

int my_uart_register(void)
{
    rt_device_t dev = &uart1_dev.parent;

    dev->type    = RT_Device_Class_Char;
#ifdef RT_USING_DEVICE_OPS
    dev->ops     = &my_uart_ops;
#else
    dev->init    = my_uart_init;
    dev->open    = my_uart_open;
    dev->close   = my_uart_close;
    dev->read    = my_uart_read;
    dev->write   = my_uart_write;
    dev->control = my_uart_control;
#endif

    return rt_device_register(dev, "uart1", RT_DEVICE_FLAG_RDWR);
}
INIT_BOARD_EXPORT(my_uart_register);   /* 自动初始化 */

应用层使用

c
#include <rtthread.h>
#include <rtdevice.h>

void uart_sample(void)
{
    rt_device_t uart;
    char buf[64];
    rt_ssize_t len;

    /* 查找设备 */
    uart = rt_device_find("uart1");
    if (!uart) {
        rt_kprintf("uart1 not found\n");
        return;
    }

    /* 打开设备(中断接收模式) */
    rt_device_open(uart, RT_DEVICE_FLAG_INT_RX);

    /* 配置波特率 */
    struct serial_configure cfg = RT_SERIAL_CONFIG_DEFAULT;
    cfg.baud_rate = BAUD_RATE_9600;
    rt_device_control(uart, RT_DEVICE_CTRL_CONFIG, &cfg);

    /* 发送数据 */
    const char *msg = "Hello RT-Thread!\r\n";
    rt_device_write(uart, 0, msg, rt_strlen(msg));

    /* 接收数据 */
    len = rt_device_read(uart, 0, buf, sizeof(buf) - 1);
    if (len > 0) {
        buf[len] = '\0';
        rt_kprintf("Received: %s\n", buf);
    }

    rt_device_close(uart);
}

RT-Thread 内核同步原语

c
/* 信号量 */
rt_sem_t sem = rt_sem_create("my_sem", 0, RT_IPC_FLAG_FIFO);
rt_sem_release(sem);
rt_sem_take(sem, RT_WAITING_FOREVER);
rt_sem_take(sem, rt_tick_from_millisecond(1000));
rt_sem_delete(sem);

/* 互斥锁(支持优先级继承) */
rt_mutex_t mutex = rt_mutex_create("my_mutex", RT_IPC_FLAG_PRIO);
rt_mutex_take(mutex, RT_WAITING_FOREVER);
rt_mutex_release(mutex);

/* 消息队列 */
rt_mq_t mq = rt_mq_create("my_mq", sizeof(my_msg_t), 10, RT_IPC_FLAG_FIFO);
rt_mq_send(mq, &msg, sizeof(msg));
rt_mq_recv(mq, &msg, sizeof(msg), RT_WAITING_FOREVER);

/* 邮箱(传递指针,效率高) */
rt_mailbox_t mb = rt_mb_create("my_mb", 10, RT_IPC_FLAG_FIFO);
rt_mb_send(mb, (rt_ubase_t)ptr);
rt_mb_recv(mb, (rt_ubase_t *)&ptr, RT_WAITING_FOREVER);

自动初始化机制

RT-Thread 提供分级自动初始化,无需手动调用:

c
/* 按初始化阶段分级 */
INIT_BOARD_EXPORT(fn);      /* 板级初始化(最早) */
INIT_PREV_EXPORT(fn);       /* 纯软件初始化 */
INIT_DEVICE_EXPORT(fn);     /* 外设驱动初始化 */
INIT_COMPONENT_EXPORT(fn);  /* 组件初始化 */
INIT_ENV_EXPORT(fn);        /* 环境初始化 */
INIT_APP_EXPORT(fn);        /* 应用初始化(最晚) */

FinSH 命令行调试

c
/* 注册调试命令 */
static int uart_test(int argc, char *argv[])
{
    rt_kprintf("UART test\n");
    return 0;
}
MSH_CMD_EXPORT(uart_test, test uart driver);

/* 在 FinSH 中执行 */
/* msh > uart_test */

褚成志的笔记