原创 finish shell分析之底层usart

2015-4-4 17:39 468 0 分类: MCU/ 嵌入式 文集: RT-Thread

rt_thread的finsh shell系统不愧是调试的一项利器,它可以除了完成一般shell的功能外,甚至还可以自定义命令。这个对功能单一的嵌入式系统来说是十分可贵的。在此我并不想对finsh shell具体有哪些功能再多做赘述,这些都可以在rt_thread的官方文档上找到,我主要想说明的是finsh shell完成功能的这个大致的过程。

 

   finsih shell的底层部分是usart,具体是又那个usart口完成就靠finsh_set_device指定。本人的硬件平台是stm32f103ze,这里rt_thread使用的是usart1,可能是考虑到调试时候的方便,usart1正好也是控制台的输出口。虽然有两套系统使用usart1,但基于rt_thread的驱动机制,这两者是不会冲突的。现在我来说明uasrt驱动是如何在rt_thread里完成注册、初始化以及顺利使用的。

 

不同于其他驱动,usart的驱动开始的相当早,在中断、时钟、FSMC的之后就轮到它初始化了。毕竟usart承担着系统控制台的输出的任务,只有在它完成后,系统之后的信息才能被打印在终端上,之后所遇到的问题才能显现出来,因此能够越早启动uasrt自然是越好的。

 

  在stm32的平台上rt_thread使用的是usart1,关于其硬件配置和stm32一般配置相同于,不再赘述,我们关注的是usart1是如何与rt_thread联系起来的。在此之前先介绍rt_thread的驱动的核心rt_device结构体。rt_device

  

  调用rt_hw_serial_register之后,rt_device以rt_object的形式被rt_thread组织起来,在后面我们可以很方便的通过rt_device_find利用之前注册的名字来找到相应的设备,事实是之后看见的finsh_set_device函数就是这么做的。而flag和通用接口函数可以连接上层和底层,完成相应的设备操作。rx_indiacate和tx_complete同样也是联系上下层的接口,但与前者是完成上层到底层操作不同的是,它们是通过中断调用向上层传递特定的信息。最后private是存放设备私有变量的地方,之前的部分还是rt_thread通用的架构,而private则是对于底层特定操作或是存放特定数据的地方,熟悉linux内核的同学一定对这种结构的形式非常熟悉,因为在内核特别是在驱动中这是经常使用的手段。

 

   rt_hw_serial_register之后,usart1在硬件上已经配置好了,设置为正常的发送和中断的接受,而且已经把其注册塞入rt_thread的核心object的管理架构中了。但是我们此时还是没有完成usart的设备的初始化,毕竟private部分,我们还没有配置呢。

 

  之后系统会将所有注册的设备都初始化一边,调用的是rt_device->init函数,对于usart1,就是rt_serial_init,它来完成我们之前没有完成的private部分的设置了。由于usart1没有使用dma发送,唯一需要配置的就是int_rx部分。uasrt1是采用中断接受的方式,像大多数操作系统一样,需要在底层设立专门的数据缓存区,方便上层以同步或是异步的方式进行读写。这里int_rx采用的是典型的环形缓存区。


Untitled document (1)   

  在usart接受中断调rt_hw_serial_isr,获取一个数据save_index加1,而上层调rt_serial_read读取串口数据,读取一个read_index加1,两者一旦到达边界就回到数据区头。一旦read_index=save_index就认为环形缓存区数据已经取空,而save_index=read_index-1的时候则认为缓存区已满。针对缓存已满的情况下,save_index和read_index同时加1,相当于丢弃了最老的数据。usart中断是随时可能发生的,上层是如何得知环形缓存区数据更新的呢?之前在rt_device的rx_indicata就起了关键作用,一旦上层某个部分要求串口接收数据,它就会调rt_device_set_rx_indicate,加自己的回调函数赋给rx_indicate,一旦中断发生,接收新数据后,就会调用上层赋给的rx_inidate函数来执行上层的接受操作。在finish shell里我们通过finsh_set_device注册了finsh_rx_ind函数,这个函数完成的功能很简单,就是将全局变量finsih_shell这个结构体里的rx_sem给释放了。具体rt_thread的信号量同步问题,如果要说的就扯的远了,这里就不多说了。只是说下这个操作的结果是唤醒了我们下一篇要讲的finish shell最重要的进程tshell,让它来处理接受的数据。

 

  至于usart1的发送部分,由于没有采用dma模式,rt_serial_write 就非常简单了,也就是最简单的发一个等一个不停的发直到发完为止,实在没什么好说的。而下一篇我将涉及finish非常重要的一个部分“语法解释”,它才是finish shell关键难点之一。

转载自:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=25788300&id=3395425

广告

文章评论 0条评论)

登录后参与讨论
相关推荐阅读
潇洒哥 2015-07-08 16:01
位操作符的使用技巧
在C语言编程中,数据的位是可以操作的最小数据单位,理论上可以用“位运算”来完成所有的运算和操作。一般的位操作是用来控制硬件的,或者做数据变换使用,但是,灵活的位操作可以有效地提高程序运行的效...
潇洒哥 2015-04-01 21:29
__main() 和 main()
因为我们通常在BOOTLOADER中都已做好了比较细致的初始化工作,包括代码的搬运,所以我们最好别再调用库函数__main(),因为__main()作为ADS集成好的库函数,会对系统进行初始化设置...
潇洒哥 2015-03-26 22:54
RT-Thread学习之scons篇--解析rtconfig.py文件
rtconfig.py文件,主要用于指定编译器以及安装路径。除此之外,该文件中定义了大量的变量,这些变量包括编译选项,汇编选项,链接选项。   import os # toolchain...
潇洒哥 2015-03-26 22:53
RT-Thread学习之scons篇--SConsruct脚本文件解析
       scons的构建文件名称是统一的都称为SConstruct。其是scons所接受的编译脚本主文件。当然为了方便目录的组织,也允许在各个目录下面存放SConscript, 然后最上面S...
潇洒哥 2015-03-26 22:53
RT-Thread学习之scons篇--SConcript文件解析
SConscript文件是用来指定哪些文件会加入编译。先来分析下BSP主目录下的SConscript文件: import rtconfig Import('RTT_ROOT') fro...
广告
我要评论
0
0
广告
关闭 热点推荐上一条 /1 下一条