这是最新(主)开发分支的文档。如果您正在查找以前版本的文档,使用左侧的下拉菜单选择所需的版本。

设备表

简介

WM IoT SDK 使用设备表对设备进行配置管理,驱动代码和设备配置分离,使用更为方便。

设备表当前使用 C 语言文件来配置。

WM IoT SDK 当前使用的 C 语言配置文件默认位置为 components/wm_dt/config/wm_dt_hw.ccomponents/wm_dt/config/wm_dt_hw.h

当用户需要修改配置文件时,不推荐直接修改组件目录中的默认文件, 而是推荐从组件目录中复制一份至工程目录(例如复制至 main/dt 目录下), 然后修改工程目录下 main 组件中的 CMakeLists.txt 文件,添加

set(ADD_DT_C_FILES "dt/wm_dt_hw.c")
set(ADD_DT_H_FILES "dt")

甚至,希望使用多份配置文件时,可为:

set(ADD_DT_C_FILES "dt/dt_config1.c"
                   "dt/dt_config2.c"
                   )

set(ADD_DT_H_FILES "dt"
                   )

请注意,在工程目录中添加配置文件时,需保持 wm_dt_hw.h 文件名称不能变。 .c 文件可以任意改名。 在多份配置文件时,需要修改文件中的配置内部名称,让每份配置的内部名称不同。 如 dt_config1.c 配置内部名称为 my_config1

WM_DT_TABLE_DEFINE(my_config1, (sizeof(dt_hw_table_entry) / sizeof(dt_hw_table_entry[0])), (void *)&dt_hw_table_entry[0]);

dt_config2.c 配置内部名称为 my_config2

WM_DT_TABLE_DEFINE(my_config2, (sizeof(dt_hw_table_entry) / sizeof(dt_hw_table_entry[0])), (void *)&dt_hw_table_entry[0]);

C 语言配置文件格式

WM IoT SDK 使用的 C 语言配置文件,其中内容由如下格式组成(摘选了部分):

typedef struct {
    uint8_t init_level;
    uint8_t init_priority;
} wm_dt_hw_init_cfg_t;

typedef struct {
    uint8_t irq_num; /**< @ref wm_irq_no_t */
    uint8_t irq_priority;
} wm_dt_hw_irq_cfg_t;

typedef struct {
    uint8_t pin_num;  /**< @ref wm_gpio_num_t */
    uint8_t pin_mux;  /**< @ref wm_gpio_pin_mux_t */
    uint8_t pin_dir;  /**< @ref wm_gpio_dir_t */
    uint8_t pin_pupd; /**< @ref wm_gpio_pupd_t */
} wm_dt_hw_pin_cfg_t;

typedef struct {
    int baudrate;      /**< @ref wm_uart_baudrate_t */
    uint8_t parity;    /**< @ref wm_uart_parity_t */
    uint8_t stop_bits; /**< @ref wm_uart_stop_bits_t */
    uint8_t data_bits; /**< @ref wm_uart_data_bits_t */
    uint8_t flow_ctrl; /**< @ref wm_uart_flowctrl_t */
} wm_dt_hw_uart_cfg_t;

typedef struct {
    wm_dt_hw_init_cfg_t init_cfg;
    uint32_t reg_base;
    wm_dt_hw_irq_cfg_t irq_cfg;
    wm_dt_hw_uart_cfg_t uart_cfg;
    uint8_t pin_cfg_count;
    wm_dt_hw_pin_cfg_t *pin_cfg;
    char *dma_device_name;
} wm_dt_hw_uart_t;

typedef struct {
    wm_dt_hw_init_cfg_t init_cfg;
    uint32_t reg_base;
    wm_dt_hw_irq_cfg_t irq_cfg;
} wm_dt_hw_timer_t;
const static wm_dt_hw_pin_cfg_t dt_hw_uart0_pin[4] = {
    [0] = { .pin_num = WM_GPIO_NUM_35, .pin_mux = WM_GPIO_IOMUX_FUN1, .pin_dir = WM_GPIO_DIR_INPUT, .pin_pupd = WM_GPIO_FLOAT },
    [1] = { .pin_num = WM_GPIO_NUM_36, .pin_mux = WM_GPIO_IOMUX_FUN1, .pin_dir = WM_GPIO_DIR_INPUT, .pin_pupd = WM_GPIO_FLOAT },
    [2] = { .pin_num = WM_GPIO_NUM_37, .pin_mux = WM_GPIO_IOMUX_FUN1, .pin_dir = WM_GPIO_DIR_INPUT, .pin_pupd = WM_GPIO_FLOAT },
    [3] = { .pin_num = WM_GPIO_NUM_38, .pin_mux = WM_GPIO_IOMUX_FUN1, .pin_dir = WM_GPIO_DIR_INPUT, .pin_pupd = WM_GPIO_FLOAT },
};

const static wm_dt_hw_uart_t dt_hw_uart0 = {
    .init_cfg        = { .init_level = 1, .init_priority = 50 },
    .reg_base        = 0x40010600,
    .irq_cfg         = { .irq_num = WM_IRQ_UART0, .irq_priority = 0 },
    .uart_cfg        = { .baudrate  = WM_UART_BAUDRATE_B115200,
                        .parity    = WM_UART_PARITY_NONE,
                        .stop_bits = WM_UART_STOP_BIT_1,
                        .data_bits = WM_UART_DATA_BIT_8,
                        .flow_ctrl = WM_UART_FLOW_CTRL_DISABLE },
    .pin_cfg_count   = sizeof(dt_hw_uart0_pin) / sizeof(dt_hw_uart0_pin[0]),
    .pin_cfg         = (wm_dt_hw_pin_cfg_t *)dt_hw_uart0_pin,
    .dma_device_name = "dma",
};

const static wm_dt_hw_uart_t dt_hw_timer0 = {
    .init_cfg    = { .init_level = 0,         .init_priority = 50 },
    .reg_base    = 0x40011800,
    .irq_cfg     = { .irq_num = WM_IRQ_TIMER, .irq_priority = 0   },
};

C 语言配置文件中的各选项比较直观,此处不在细述含义。

备注

务必注意 pincfg 的设定,避免超过当前SOC所支持范围的定义 或 定义冲突。

比如:所定义的 GPIO_NUM 并非当前 SOC 所支持的范围,1个 pin 被多个设备定义等场景。

具体可参考 Pinmux

使用设备表

一般在使用时,用户只需使用 wm_device_t *wm_dt_get_device_by_name(const char *device_name) 从设备表中获取到设备使用即可。

typedef struct {
    char *name; /**< device name */

    void *hw; /**< hardware info, ref wm_dt_hw_xxx_t */

    void *ops; /**< device operation interface */
    void *drv; /**< driver context data */

    wm_device_status_t state; /**< device state */

    void *priv; /**< user private data */
} wm_device_t;

其中,hw 指针指向配置文件中的信息,由各驱动模块自行使用。

对于使用多份配置文件的场景,可通过配置文件的预设的名称进行选择使用,在代码中使用 int wm_dt_set_device_table_name(const char *default_name) 接口即可。

新增设备

可参考默认的配置文件,仿照 uart 设备添加新增设备的 hw 结构和 ops 结构即可。

在设备数据结构添加之后,更新设备表,如:

const static struct wm_dt_table_entry dt_hw_table_entry[3] = {
    [0] = { .dev_name = "uart0",  .hw_addr = (void *)&dt_hw_uart0,  .ops_addr = (void *)&wm_drv_uart_ops  },
    [1] = { .dev_name = "uart1",  .hw_addr = (void *)&dt_hw_uart1,  .ops_addr = (void *)&wm_drv_uart_ops  },
    [2] = { .dev_name = "timer0", .hw_addr = (void *)&dt_hw_timer0, .ops_addr = (void *)&wm_drv_timer_ops },
};

WM_DT_TABLE_DEFINE(default, 3, (void *)&dt_hw_table_entry[0]);

其中,使用 WM_DT_TABLE_DEFINE(name, count, addr) 注册给设备表时,可以通过填写不同的名称,达到设置多份配置文件的目的。

C 语言数据结构的规则

最终使用的 C 语言数据结构中,对于每个设备的 hw 结构体有如下约定:

typedef struct {
    wm_dt_hw_init_cfg_t init_cfg;
    /* more ... */
} wm_dt_hw_xxx_t;

即 hw 结构体中的第一个成员必须为 init_cfg

init_cfg 表示该设备的初始化配置信息,将在未来版本中生效(当前版本还未实际使用)。其包含两个成员选项:
  • init_level 表示初始化方式,

    取值为 1 表示由系统自动完成该设备初始化,

    取值为 0 表示由用户自己完成该设备初始化。

  • init_priority 表示初始化优先级,取值为十进制整数,取值范围 0 - 100,

    取值越大表示优先级越高,优先级高的先初始化。相同优先级的设备在这一优先级被随机初始化。

对于每个设备的 ops 结构体有如下约定:

typedef struct {
    int (*init)(wm_device_t *dev);
    int (*deinit)(wm_device_t *dev);
    /* more ... */
} wm_drv_xxx_ops_t;

即 ops 结构体中的前两个成员必须为 init 函数和 deinit 函数。

API 参考

可参考 DT 参考