0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

基于serialX串口驱动移植freemodbus

冬至子 来源:出出啊 作者:出出啊 2023-10-13 14:54 次阅读

关于 serialX
之前,笔者写过多篇 serialX 的文章,已经把它的原理和理念完完全全明明白白讲了,包括它的优势以及使用它需要注意的方面和可能遇到的问题。

到目前为止,笔者只介绍了 finsh/msh 使用 serialX ,实现了中断接收中断发送模式打开串口设备,这次尝试让笔者坚信了即便使用 DMA 收发也能在 finsh 里应付自如。今天我们尝试一下在 freemodbus 里使用 serialX 。

注:笔者写过文章,讨论在控制台或者 finsh 里完全的中断收发或者完全的 DMA 收发会有哪些问题。有兴趣的大家可以找找看。

测试环境
笔者手里有一块儿 NK-980IOT V1.0 的开发板,这是去年 rt-thread 论坛搞的测评活动送的。一方面,它吃灰很久了,另一方面,serialX 的驱动很久没新增了。趁此机会,笔者把 NUC980 的 serialX 驱动加上,然后在此基础上调试出 console 和 finsh,最后移植 freemodbus 试试会遇到什么问题。

NUC980 serialX 驱动
之前,笔者介绍 serialX 的时候,曾详细的讲解过 struct rt_uart_ops 接口中的每一个函数的功能。完全按照每一个函数功能定义去做,后面的事情就是水到渠成的。

花了小半天的时间从 drv_uart.c 改成 drv_uartX.c 。

然后使用 serialX 中提供的 测试程序 serialX_test.c 简单测试了一下,收发回环没发现严重问题(没有数据丢失,没有数据错误)。

启用控制台和 finsh 。改成“中断收发读写”模式,试了几个命令,打印结果完整。

可以说,验证了这次写的驱动还是很不错的,是成功的。

启用 freemodbus
env 环境里启用 freemodbus,打开 modbus master 并添加 master 的测试程序。
使用命令 pkgs --update 下载 freemodbus 源码。

打开项目后,我们可以看到 “sample_mb_master.c” “port” 开头的以及几个 “mb” 开头的。”sample_mb_master.c” 文件是测试样例程序,”port” 开头的文件是 freemodbus 在 rt-thread 系统上的接口,剩余的是 freemodbus 的核心程序。

这里面 “sample_mb_master.c” “portserial_m.c” 这两个文件是今天我们最关心的。我们可以打开看看这俩文件都做了啥。

“sample_mb_master.c”
这个文件的主要工作是创建了两个线程。

一个用来循环调用 eMBMasterPoll 函数,这个函数是 freemodbus 工作引擎。不循环执行这个函数 freemodbus 跑不起来。

另一个模式应用层线程,用来发送多寄存器写请求(在这个样例程序里只用这个来做演示)。

“portserial_m.c”
这个文件里是串口设备操作相关的。比如初始化、打开、关闭,写数据到串口设备,从串口设备读数据等等。

xMBMasterPortSerialInit
笔者第一次打开这个文件,满眼看到的 serial->config. serial->ops->configure 等操作把我惊呆了。

初始化过程最后创建了子线程 serial_soft_trans_irq ,它的工作就是发送数据。

serial_soft_trans_irq
发送子线程入口函数,这个函数只关心 EVENT_SERIAL_TRANS_START 事件,接收到事件后调用 xMBMasterRTUTransmitFSM 函数,如果数据没发送完,调用 xMBMasterPortSerialPutByte->xMBMasterPortSerialPutByte 往串口写 1 个字节数据。循环执行直到把所有需要发送的数据写完。

第一次测试
经过简单浏览后,笔者想尽快运行程序,做进一步观察。

计算机端,笔者用一个 Qt5 写的 modbus slave 终端。如果一切顺利,NK-980IOT 开发板上发的多寄存器写请求会对 Qt5 modbus slave 终端里的数据修改,并界面上显示到数据变化。

很幸运,笔者这一步也很顺利。

进一步测试
因为自带的 master 样例程序仅仅测试了一个多寄存器写,而且,我们可以看到原来只对 eMBMasterReqWriteMultipleHoldingRegister 返回错误代码计数,并没有区分判断会出现哪种错误,我们把这个错误码处理一下

rt_uint32_t err_no = 0, err_reg = 0, err_arg = 0, err_data = 0, err_tout = 0;
switch (error_code) {
case MB_MRE_NO_ERR:
    err_no++;
break;
case MB_MRE_NO_REG:
    err_reg++;
break;
case MB_MRE_ILL_ARG:
    err_arg++;
break;
case MB_MRE_REV_DATA:
    err_data++;
break;
case MB_MRE_TIMEDOUT:
    err_tout++;
break;
default:
    rt_kprintf("n:%d; r:%d; a:%d; d:%d; t:%dn", err_no, err_reg, err_arg, err_data, err_tout);
break;
}

这几种返回码,只有 MB_MRE_NO_ERR 是正常和完美的,如果出现其它几个都是有问题的。

笔者经过关闭 slave 端,可以测试出现 MB_MRE_TIMEDOUT 。但是,经常还会出现 MB_MRE_REV_DATA 这个错误!!!

MB_MRE_REV_DATA 错误跟踪
这个错误字面含义是,有接收数据,但是接收的数据有异常!我们上面的测试只有一个“多寄存器写”,master 发写请求了以后,只有可能收到成功响应(MB_MRE_NO_ERR),或者错误响应信息(MB_MRE_NO_REG MB_MRE_ILL_ARG)。不应该会出现 slave 给 master 主动发请求的。

为了观察 slave 端接收和发送数据,笔者计划把 slave 端的调试打开,检查一下它是不是回复响应出现错误了。

因为笔者的 slave 端是 Qt 写的,当前使用的这个 exe 是很久之前用 Qt5.9 版本编译出来的。笔者需要重新编译一下这个 exe 程序(现在安装的版本有 Qt5.12 Qt5.15 两个)。编译出来新程序之后,笔者得到如下调试信息(无论是 Qt5.12 还是 Qt5.15),

qt.modbus.lowlevel: (RTU server) Received ADU: "01100000000408000f0049000200003574"
qt.modbus: (RTU server) Request PDU: 0x100000000408000f004900020000
qt.modbus: (RTU server) Response PDU: 0x1000000004
qt.modbus.lowlevel: (RTU server) Response ADU: "011000000004c1ca"
qt.modbus.lowlevel: (RTU server) Received ADU: "011000000004080013004b000200009175"
qt.modbus: (RTU server) Request PDU: 0x1000000004080013004b00020000
qt.modbus: (RTU server) Response PDU: 0x1000000004
qt.modbus.lowlevel: (RTU server) Response ADU: "011000000004c1ca"
qt.modbus.lowlevel: (RTU server) Received ADU: "011000000004080027004d000200006cb6"
qt.modbus: (RTU server) Request PDU: 0x1000000004080027004d00020000
qt.modbus: (RTU server) Response PDU: 0x1000000004
qt.modbus.lowlevel: (RTU server) Response ADU: "011000000004c1ca"

slave 断得到了完整正确的 ADU,响应的 ADU 也是正常的。接下来再回过头看看开发板接收响应 ADU 时得到的数据是什么。
在 eMBMasterRTUReceive 函数体内 if 条件语句之前添加一句代码 od_mem((unsigned int)ucMasterRTURcvBuf, (unsigned int)ucMasterRTURcvBuf + usMasterRcvBufferPos);。这句代码将在控制台打印输出接收到的 ADU 。

笔者看到了很多 “01040004 70F9C1” “01040004 70F9F9” 或者其它数据,但是正确的应该是 “01100000 0004C1CA”,很多次才出现一次正确的。为什么从串口发出去的数据是正确的,能被远端正常接收,远端响应回来的数据就出现接收错误了?!

为了确定开发板和驱动工作还是正常的,笔者又切换到 serialX 的测试程序,用收发回环测试一遍没有问题,再测试 freemodbus 接收仍然异常!

修改 xMBMasterPortSerialInit
前边笔者说过,当看到 serial->config. serial->ops->configure 等操作时惊呆了。这一步,让上帝的归上帝吧。

serial_dev = rt_device_find(uart_name);
if(serial_dev == RT_NULL)
{
    /* can not find uart */
    return FALSE;
}
/* set serial configure parameter */
uart_conf.baud_rate = ulBaudRate;
/* set serial configure */
rt_device_control(serial_dev, RT_DEVICE_CTRL_CONFIG, &uart_conf);
/* open serial device */
if (!rt_device_open(serial_dev, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_INT_TX)) {
    rt_device_set_rx_indicate(serial_dev, serial_rx_ind);
} else {
    return FALSE;
}

全局变量 static struct rt_serial_device *serial; 改成 static rt_device_t serial_dev = RT_NULL;。所有使用 serial 这个变量的地方全换成使用 serial_dev 。

这样修改了以后,一切变得明朗了起来。

总结

除了上面提到的那个问题,笔者还遇到一种情况,slave 端接收串口数据经常出现断帧,而且字符接收间隔长达 10+ms 。这种情况,当笔者将 rt_device_write(serial_dev, 0, pucByte, 1); 改成 rt_device_write(serial_dev, 0, pucByte, sz); 后得到解决。但是,之后再也没复现。

得益于 serialX 的框架理念,我们可以从“一个字节一个字节的写”提升到“写一批字节”。而且放到发送缓存里的数据,无论使用中断发送还是 DMA 发送都不会对应用层带来任何压力。

另一方面,读 modbus ADU 的时候,其实也可以“读一批字节”。不是一个字节中断,read 一个字节,下一个接收字节中断,再 read 一个字节…

freemodbus 还有很多可圈可点的地方。但是拿它来验证 serialX 驱动可能是最简单的一个了。

最后,笔者把修改过后的 ‘portserial_m.c’ 文件上传上来,但是请大家注意,不止这一个文件需要修改,但是其它修改都是因为这个文件引起的。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 寄存器
    +关注

    关注

    30

    文章

    5037

    浏览量

    117763
  • 缓存器
    +关注

    关注

    0

    文章

    63

    浏览量

    11579
  • 串口驱动
    +关注

    关注

    2

    文章

    78

    浏览量

    18349
  • FreeModbus
    +关注

    关注

    0

    文章

    16

    浏览量

    4362
  • serialX
    +关注

    关注

    0

    文章

    7

    浏览量

    786
收藏 人收藏

    评论

    相关推荐

    请问stm32cube ide如何编译底层库?

    把之前在mdk5中编译正常的freemodbus 移植到 cube ide 后,无法编译通过。 看debug 是 无法编译m3的底层库的方法。cmsis_gcc.h D
    发表于 04-10 07:35

    usb转串口线怎么使用 usb转串口串口转usb的区别

    )进行通信。因此,通过使用USB转串口线,可以将现代计算机与串口设备连接起来,实现数据传输和通信。 在使用USB转串口线之前,需要先安装适当的驱动程序。这些
    的头像 发表于 01-22 14:56 1209次阅读

    【AWTK开源智能串口屏方案】HMI端程序移植编译及运行

    本篇文章介绍一下AWTK开源智能串口屏方案的串口屏端(即HMI端)的编译运行步骤,并介绍如何将HMI端移植到Linux或STM32平台或RTOS平台,以及如何配置资源文件。引言:AWTK-HMI
    的头像 发表于 01-18 08:24 296次阅读
    【AWTK开源智能<b class='flag-5'>串口</b>屏方案】HMI端程序<b class='flag-5'>移植</b>编译及运行

    移植uart驱动至μc/cosIII中,PC串口无输出显示的原因?如何解决?

    刚接触uc/cosIII,由于开发需要,有关驱动移植的问题需向你们请教,希望能得到你们的帮忙,谢谢! 环境:win7 + IAR7.70.2 + Jlink + ADSP-CM408F-EZKIT
    发表于 01-11 08:12

    台达串口DVP系列驱动如何使用?

    详细介绍如何使用台达串口DVP系列驱动
    发表于 12-29 11:06 0次下载

    如何将FreeMODBUS协议栈移植到AT32F43x单片机方法

    电子发烧友网站提供《如何将FreeMODBUS协议栈移植到AT32F43x单片机方法.pdf》资料免费下载
    发表于 12-18 11:15 0次下载
    如何将<b class='flag-5'>FreeMODBUS</b>协议栈<b class='flag-5'>移植</b>到AT32F43x单片机方法

    飞凌OK113i-C全志T113-i开发板rtl8723du WIFI功能测试及蓝牙驱动移植

    飞凌 OK113i-C 全志T113-i开发板板载一个RTL8723du wifi/蓝牙二合一模块,板子出厂已经移植好了WIFI驱动但是蓝牙驱动没有,所以这篇文章我们主要做蓝牙驱动
    的头像 发表于 12-11 13:52 1032次阅读

    如何将FreeMODBUS协议栈移植到AT32F43x单片机

    本应用笔记介绍了如何将FreeMODBUS协议栈移植到AT32F43x单片机方法。本文档提供的源代码演示了使用Modbus的应用程序。单片机作为Modbus从机,可通过RS485或RS232与上位机相连,与Modbus Poll调试工具(Modbus主机)进行通讯。
    发表于 10-26 06:18

    STM32 USB虚拟串口驱动

    电子发烧友网站提供《STM32 USB虚拟串口驱动.rar》资料免费下载
    发表于 10-09 15:25 55次下载
    STM32 USB虚拟<b class='flag-5'>串口</b><b class='flag-5'>驱动</b>

    freemodbus可用在主机上吗?

    freemodbus可用在主机上么
    发表于 10-09 06:40

    在STM32F407VGT6上使用serialX的步骤

    新建RTthread STM32F407VGT6项目。打开CUBEMAX配置调试口,外部时钟,串口1(控制台),串口3,串口开启中断,生成代码。
    的头像 发表于 08-24 17:49 778次阅读
    在STM32F407VGT6上使用<b class='flag-5'>serialX</b>的步骤

    基于serialX串口驱动移植libmodbus的步骤

    之前,笔者介绍 serialX 的时候,曾详细的讲解过 struct rt_uart_ops 接口中的每一个函数的功能。完全按照每一个函数功能定义去做,后面的事情就是水到渠成的。
    发表于 08-10 15:25 352次阅读

    Linux驱动移植 Linux系统架构优点

    系统移植 linux 驱动移植 移植是说同样的一个 linux 操作系统,我们可以跑到不同的硬件上面,我们把操作系统移植到不同的硬件上面,这
    的头像 发表于 07-27 17:06 570次阅读
    Linux<b class='flag-5'>驱动</b><b class='flag-5'>移植</b> Linux系统架构优点

    【灵动微】FTHR-G0140开发板移植RT-Thread驱动

    灵动微G0140移植RT-Thread驱动
    的头像 发表于 06-05 13:45 21.6w次阅读
    【灵动微】FTHR-G0140开发板<b class='flag-5'>移植</b>RT-Thread<b class='flag-5'>驱动</b>

    请教freemodbus只支持从机地址连续怎么解读?

    freemodbus官方文档中目前协议栈只支持从机地址连续,并且起始地址从1开始。这句话是什么意思呢?
    发表于 05-17 14:34