RT-Thread动态模块mo调试设备驱动小结【mo实现linux中ko功能】

 前言

 动态驱动模块的调试可以减少烧录过程,对于调试来说是一件很快乐的事情。
 rtt中有动态模块概念,而且和linux中的命名类似为分为mo和so,其中mo在笔者浅显的理解即类似于linux中的elf,即可执行文件。同时linux中的ko也是elf文件一种,所以想rtt中的mo和linux中的ko是否可以实现同样的功能。以下以uart串口驱动模块的动态加载调试作为示例讲解整个操作流程。 

正文

准备步骤

首先是准备步骤:搭建环境,编译生成mo。这里可以参考RT_Thread编程指南中的28节 动态模块章节,使用过程中注意linux环境中也需要设置环境变量(RTT_ROOT、BSP_ROOT)。
我这里使用的是github仓库中的hello模块。编译生成hello.mo,在msh中执行hello,输出hello,这一步工作完成。

编译驱动mo

 接下来是编译生成uart的设备驱动,并且注册到rtt的设备驱动管理框架中。以下是hello.c中的代码,代码比较多,截取了主要部分,因为针对于不同平台的串口初始化函数是不一样的。在main中调用rt_hw_uart_init();实现对串口驱动的注册。

int rt_hw_uart_init(void)
{
    struct rt_serial_device *serial;
    struct device_uart      *uart;
    struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;

    static struct rt_serial_device serial1;
    static struct device_uart      uart1;

    serial  = &serial1;
    uart    = &uart1;

    serial->ops              = &_uart_ops;
    serial->config           = config;
    serial->config.baud_rate = 115200;

    rt_hw_serial_register(serial,
                            "uart1",
                            RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX,
                            uart);
    return 0;
}
int main(int argc, char *argv[]) 
{
    printf("hello world from RTT::dynamic module\n"); 
    rt_hw_uart_init();
    return 0; 
}

这里会出现两个问题:


问题一:动态模块加载缺少函数符号问题

     RT-Thread-动态模块加载缺少函数符号问题RT-Thread问答社区 - RT-Thread

问题二:动态驱动模块加载报错【rt_object_init】是否存在bug?

     RT-Thread-动态驱动模块加载报错【rt_object_init】是否存在bug?RT-Thread问答社区 - RT-Thread
以上是针对两个问题的解决方式。具体问题和解决方案请查看文章内容。针对问题二做一下补充说明:

#ifdef RT_USING_MODULE
    if (module)
    {
        if(rt_strcmp(object->name,"uart1") == 0)
        {
            rt_list_insert_after(&(information->object_list), &(object->list));
            object->module_id = (void *)module;
        }
        else
        {
            rt_list_insert_after(&(module->object_list), &(object->list));
            object->module_id = (void *)module;
        }
    }
    else
#endif /* RT_USING_MODULE */
    {
        /* insert object into information object list */
        rt_list_insert_after(&(information->object_list), &(object->list));
    }

 这里 if(rt_strcmp(object->name,"uart1") == 0)比较的设备是uart1,如果你的hello.c中的注册设备是其他记得修改。这里,同时这里也是一个极其不合理的存在。正在思考如何修改。编译执行完后,在msh执行hello.c,使用指令list_device可以观察到存在uart1设备,说明运行成功。

测试驱动是否正常

编写串口测试程序

/*
 * Program list: This is a uart device usage routine
 * The routine exports the uart_sample command to the control terminal
 * Format of command: uart_sample uart2
 * Command explanation: the second parameter of the command is the name of the uart device. If it is null, the default uart device wil be used
 * Program function: output the string "hello RT-Thread!" through the serial port, and then malposition the input character
*/

#include <rtthread.h>

#define SAMPLE_UART_NAME       "uart1"

/* Semaphore used to receive messages */
static struct rt_semaphore rx_sem;
static rt_device_t serial;

/* Receive data callback function */
static rt_err_t uart_input(rt_device_t dev, rt_size_t size)
{
    /* After the uart device receives the data, it generates an interrupt, calls this callback function, and then sends the received semaphore. */
    rt_sem_release(&rx_sem);

    return RT_EOK;
}

static void serial_thread_entry(void *parameter)
{
    char ch;

    while (1)
    {
        /* Read a byte of data from the serial port and wait for the receiving semaphore if it is not read */
        while (rt_device_read(serial, -1, &ch, 1) != 1)
        {
            /* Being Suspended and waiting for the semaphore */
            rt_sem_take(&rx_sem, RT_WAITING_FOREVER);
        }
        /* Read the data from the serial port and output through dislocation */
        ch = ch + 1;
        rt_device_write(serial, 0, &ch, 1);
    }
}

static int uart_sample(int argc, char *argv[])
{
    rt_err_t ret = RT_EOK;
    char uart_name[RT_NAME_MAX];
    char str[] = "hello RT-Thread!\r\n";

    if (argc == 2)
    {
        rt_strncpy(uart_name, argv[1], RT_NAME_MAX);
    }
    else
    {
        rt_strncpy(uart_name, SAMPLE_UART_NAME, RT_NAME_MAX);
    }

    /* Find uart devices in the system */
    serial = rt_device_find(uart_name);
    if (!serial)
    {
        rt_kprintf("find %s failed!\n", uart_name);
        return RT_ERROR;
    }
    /* Initialize the semaphore */
    rt_sem_init(&rx_sem, "rx_sem", 0, RT_IPC_FLAG_FIFO);
    /* Open the uart device in interrupt receive and polling send mode */
    rt_device_open(serial, RT_DEVICE_FLAG_INT_RX);
    /* Set the receive callback function */
    rt_device_set_rx_indicate(serial, uart_input);
    /* Send string */
    rt_device_write(serial, 0, str, (sizeof(str) - 1));

    /* Create a serial thread */
    rt_thread_t thread = rt_thread_create("serial", serial_thread_entry, RT_NULL, 1024, 25, 10);
    /* Start the thread successfully */
    if (thread != RT_NULL)
    {
        rt_thread_startup(thread);
    }
    else
    {
        ret = RT_ERROR;
    }

    return ret;
}
/* Export to the msh command list */
MSH_CMD_EXPORT(uart_sample, uart device sample);

在msh中输入uart_sample,驱动打开,初始化正常。观察uart1工作是否正常。正常说明驱动加载运行正常。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值