This is the documentation for the latest (main) development branch. If you are looking for the documentation of previous releases, use the drop-down menu on the left and select the desired version.

Device Table

Overview

The device table currently using C language files,

the default location for the C language configuration files used by the WM IoT SDK is components/wm_dt/config/wm_dt_hw.c and components/wm_dt/config/wm_dt_hw.h.

When you need to modify the configuration file, it is recommended not to modify the default files in the component directory directly. Instead, it is recommended to copy them to the project directory (e.g., copy to the main/dt directory), and then modify the CMakeLists.txt file in the main component of the project directory to add

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

If you want to use multiple configuration files, you can set it as follows:

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

set(ADD_DT_H_FILES "dt"
                   )

C Language Configuration File Format

The C language configuration files used by the WM IoT SDK consist of the following format (partial excerpt):

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 {
    char *device_name;
    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 {
    char *device_name;
    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 = {
    .device_name     = "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 = {
    .device_name = "timer0",
    .init_cfg    = { .init_level = 0,         .init_priority = 50 },
    .reg_base    = 0x40011800,
    .irq_cfg     = { .irq_num = WM_IRQ_TIMER, .irq_priority = 0   },
};

The options in the C language configuration files are intuitive and will not be further explained here.

Using the Device Table

Generally, when using it, users only need to use wm_device_t *wm_dt_get_device_by_name(const char *device_name) to get the device from the device table for use.

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;

The hw pointer points to the information in the configuration file and is used by each driver module itself.

For scenarios using multiple configuration files, they can be selected based on the preset name in the configuration file by using the int wm_dt_set_device_table_name(const char *default_name) interface in the code.

Adding New Devices

You can refer to the default configuration files and add the hw structure and ops structure for the new device by referring to the uart device.

After adding the device data structure, update the device table as follows:

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]);

When registering with the device table using WM_DT_TABLE_DEFINE(name, count, addr), different names can be provided to set up multiple configuration files.

C Language Data Structure Rules

Regardless of the configuration file method used, the C language data structure finally used must follow this convention for the hw structure of each device:

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

That is, the first two members in the hw structure must be device_name and init_cfg.

For each device’s ops structure, it must follow this convention:

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

That is, the first two members in the ops structure must be the init function and the deinit function.

API Reference

Refer to DT Reference