005——串口移植(基于鸿蒙liteos-a)

打印 上一主题 下一主题

主题 986|帖子 986|积分 2958

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x

目次
一、 Liteos-a中串口的使用
1.1 内核里打印
1.2 APP控制台
​编辑
1.2.1 /dev/console
1.2.2 /dev/serial
1.2.3 /dev/uartddev-0
1. 总体介绍
2. device_t
3. drvier_t
4. uartdev_fops
1.2.4 uart_ops
二、 鸿蒙串口内部的一些机制(流水账,新人可跳过)
三、串口移植
3.1 串口发送单个字符
3.2 在device_t中指定资源
3.3 实现uart_ops
3.4 GIC
四、启动后测试






一、 Liteos-a中串口的使用

1.1 内核里打印

内核打印函数是PRINT_RELEASE,它的内部调用关系如下:
  1. PRINT_RELEASE
  2.    LOS_LkPrint
  3.        g_osLkHook
  4.            OsLkDefaultFunc
  5.                OsVprintf
  6.                    UartPuts
  7.                        UartPutsReg
  8.                            UartPutStr
  9.                                UartPutcReg
复制代码
我们要实现UartPutcReg,用来输出单个字符。
(vscode的自动跳转太垃了,代码量大就失效了,这个图就不给各人截了。)
1.2 APP控制台

        我们编写的应用程序,调用printf时,那些信息从那里打印出来?从控制台。 在串口上运行程序,控制台就是串口。 长途登录板子后运行程序,控制台就是长途登录终端。
控制台的实现分为4层:

        据老师所讲鸿蒙对每个文件都有个inode节点,里面有个 file_operation_vfs布局体。以open函数为例,最上层console会调用inode中的open,open会向下调用inode一层层最后到实际的uart设备inode的open。从而实现了设备分层。



代码系统初始化中就对console去做了初始化,有点类似于linux的bash

1.2.1 /dev/console

        init进程打开的就是/dev/console,它会打开shell。 我们在shell里实行各种APP时,这些APP会继续父进程的3个设备:标准输入、标准输出、标准错误,都对应/dev/console。 我们编写的APP,一样平常不必要本身去打开/dev/console,它已经继续得到了。 在串口上运行程序,/dev/console就是串口。 长途登录板子后运行程序,/dev/console就是长途登录终端。 所以/dev/console表示的是当前终端,它可能对应差别的设备,好比/dev/serial或/dev/telnet。
1.2.2 /dev/serial

        在Liteos-a中,/dev/serial被称为virtual serial,假造串口。它只是起一个中转的作用,无论是APP还是内核,使用/dev/serial时,都是再次跳转去实行详细串口设备驱动程序的函数。好比:

        那么,/dev/serial这个假造串口,怎么跟详细串口挂钩?也就是上图中,GetFileOps函数为何能得到详细串口的驱动程序? 方法如下图所示:

virtual_serial_init函数会找到/dev/uartdev-0的驱动程序(即它对应的struct inode,里面含有file_operations_vfs)。

1.2.3 /dev/uartddev-0

1. 总体介绍

这是真正操纵硬件的驱动程序,它分为两部分:device_t、driver_t。


  • 在device_t中设置资源,好比寄存器物理基地点、中断号等
  • 在driver_t中提供函数,好比device_probe、device_attach函数

    • 当内核发现著名字系统的device_t、driver_t时
    • 就会调用driver_t中的device_probe、device_attach函数
    • 在里面根据device_t得到资源、注册驱动register_driver

这种写驱动程序的方法,被称为分离:操纵函数、资源分离。 以后想换一个硬件,只必要修改device_t就可以,driver_t保存稳定。
2. device_t

示例代码:

3. drvier_t

先注册一个drvier_t布局体,它里面带有各类device_method_t:

当内核发现有同名的device_t和driver_t时,就会调用driver_t里面提供的device_probe、device_attach函数。
4. uartdev_fops

在device_attach函数里从device_t里获取硬件资源、注册驱动:

/dev/uartdev-0对应的驱动程序时uartdev_fops,它通过uart_ops来操纵硬件。
1.2.4 uart_ops

在UART驱动程序里,我们只必要提供硬件操纵部分:

uart_ops里有4个函数:


  • config:配置串口,好比波特率等
  • startup:启动串口,好比注册中断处置惩罚函数、启动串口
  • start_tx:发送字符串
  • shutdown:关闭串口
串口就两大功能:发送数据、吸收数据。 在Liteos-a中,发送数据比力简朴:没有使用中断,而是使用查询方式逐个发送,核心是UartPutcReg。 吸收数据时使用中断,所以必要注册串口吸收中断处置惩罚函数,它要做的事情是:


  • 发生中断时,读取硬件得到字符,可能有多个字符
  • 处置惩罚特殊字符:好比不`\r`换为`\n`
  • 关照上层代码:udd->recv(udd, buf, count);

 

二、 鸿蒙串口内部的一些机制(流水账,新人可跳过)

        鸿蒙和别的操纵系统一样,将设备分成了driver和device。device用来形貌设备信息。driver用来做一些操纵。好比差别品牌的内存我要用它来做的事情都是一样的,这部分的代码就是driver,而详细的它每个功能寄存器的地点,中断等等则在device里。

        这是一个设备的布局体对象,它的实行顺序其实就是从上往下的,先probe在attach(得到内存资源和中断资源)在detach最后shutdown竣事。

        这里是它的一个调用过程,韦东山老师讲的这个课不太适合初学者,适合有肯定基础的人。天才除外。我指的是正凡人哦。因为我之前对linux的学习比力多加上去过很多多少公司练习,对底层的东西比力了解。鸿蒙的头脑和linux很像所以可以快速上手。随着不断的学习,我发现大佬们的头脑是同等的。许多优秀的项目都有共同的内核,这里不是操纵系统的谁人内核哦,是头脑。近来也碰到了许多的问题,还是那句话,感兴趣,有精力的同砚可以加群一起学,最好是我们一人研究一块背面在互换分享,这其实就是团队学习的意义。可以快速高效的掌握新技术。主要是我赶时间,呜呜呜呜。
        回到正题我们想要移植一个硬件设备其实就完成谁人布局体就行,比力简朴,别的的东西内核已经帮我们做了。linux驱动开辟时也是这样,完成设备布局体中必要的函数成员,把布局体一写就好了,不论简朴的设备还是复杂的设备头脑上都是这样的。

三、串口移植

我们的目的是:让最小系统启动。 那么对于串口,不必要考虑得很全面:


  • 不必要初始化串口:u-boot已经初始化串口了
  • 不必要动态配置串口:固定使用某个波特率等配置就可以(在u-boot里设置过了)
移植工作只必要实现这几点:


  • 串口发送单个字符
  • 注册串口吸收中断函数:确定中断号、使能中断、在中断函数中读取数据
3.1 串口发送单个字符


起首改下相关代码的名字


功能代码已经实现了,我们就改改地点啥的就行。

3.2 在device_t中指定资源

必要确定2个资源:寄存器地点、中断号


 这里设置串口的物理基地点

 

这里是串口的中断号


这里科普一下这里的SPI可不是谁人通讯总线哦。 
           SPI,即Shared Peripheral Interrupts,代表共享外设中断。这种中断类型来自于多个外设设备,比方IO外设等,而且这些设备共享雷同的中断线。当任何一个这些外设必要引起CPU的留意时,它们会触发SPI。由于多个设备共享同一中断线,因此中断处置惩罚程序必要能够区分是哪一个设备触发了中断,这通常通过读取中断状态寄存器来实现。
          SGI,即Software Generated Interrupts,是软件生成的中断。这种中断不是由硬件外设触发的,而是由软件程序(如操纵系统或驱动程序)通过写入特定的寄存器或实行特定的指令来生成的。SGI通常用于软件层面的通讯和变乱处置惩罚,比方使命调治、线程同步等。由于SGI是由软件控制的,因此它们具有高度的灵活性和可编程性。
          PPI,通常指CPU Private Peripheral Interrupts,即CPU私有外设中断。这是一种中断类型,用于处置惩罚CPU与私有外设之间的通讯和变乱响应。PPI在盘算机系统中扮演着重要角色,资助CPU及时响应和处置惩罚来自外设的中断请求。
  

然后


我们改成串口2,因为exynos4412的uboot初始化的是串口2的资源

然后这里也有一个坑这里必要修改 

        还有这里不是改PBASE,PBASE都没人用,改BASE或者说PBASE是base的地点,必要一个宏转化一下

想找下这个宏在哪定义的这个sg vscode恶心死了,跳转一直加载不出来,可恶。换source insight


访问假造机的IP然后映射到当地网络假造磁盘方便操纵

 新建个目次放工程文件,这里没有权限。
  1. sudo chmod -R go+rwx /home/book
复制代码


现在就没问题了

新建工程

添加vendor目次

添加kernel里的liteos-a目次

添加drivers目次

这里添加汇编文件否则会加不进来

点开后把liteos-a重新加一下,然后同步文件

有点慢等一会,别的操纵可以参考我以前的文章
Source Insight的学习_source insight read only-CSDN博客

不知道为什么要这样,猜测不能用物理地点可能要转化成对应假造地点用

这些名字也必要改



然后里面的内容做个替换

 然后我们来编译一下

        整型溢出了 
        发现鸿蒙源码的一个bug这里为什么用有符号整型啊,我基地点0x4000 0000,内存大小一个G加起来是0x8000 0000改好高出有符号整型的限定。内存映射限定在有符号整型的话岂不是意味着设备最多只能有2个G的内存。
        我在官方的社区下发了帖子不知道会不会回我。下面这个链接。有人回的话兄弟们踢我一下。
https://bbs.csdn.net/topics/618273814
这里先改小一点点。


又来咯

再给LCD让一部分空间,无语啦。
 
 
3.3 实现uart_ops

在UART驱动程序里,uart_ops布局体封装了UART的硬件操纵:

uart_ops里有4个函数:


  • config:配置串口,好比波特率等
  • startup:启动串口,好比注册中断处置惩罚函数、启动串口
  • start_tx:发送字符串
  • shutdown:关闭串口
我们只必要实现startup、start_tx,其他函数可以设为空:


  • startup:确定中断号、request_irq、使能中断、提供中断处置惩罚函数
  • start_tx:发送字符串

3.4 GIC

在kernel\liteos_a\platform\main.c中,调用OsSystemInfo打印系统信息时,代码如下:
  1.    PRINT_RELEASE("\n******************Welcome******************\n\n"
  2.            "Processor   : %s"
  3. #if (LOSCFG_KERNEL_SMP == YES)
  4.            " * %d\n"
  5.            "Run Mode    : SMP\n"
  6. #else
  7.            "\n"
  8.            "Run Mode    : UP\n"
  9. #endif
  10.            "GIC Rev     : %s\n"
  11.            "build time  : %s %s\n"
  12.            "Kernel      : %s %d.%d.%d.%d/%s\n"
  13.            "\n*******************************************\n",
  14.            LOS_CpuInfo(),
  15. #if (LOSCFG_KERNEL_SMP == YES)
  16.            LOSCFG_KERNEL_SMP_CORE_NUM,
  17. #endif
  18.            HalIrqVersion(), __DATE__, __TIME__,\
  19.            KERNEL_NAME, KERNEL_MAJOR, KERNEL_MINOR, KERNEL_PATCH, KERNEL_ITRE, buildType);
复制代码

里面的HalIrqVersion函数用到的GIC的假造地点,要正确设置,否则没有打印信息。 IMX6ULL的内存映射代码里,设备空间从GIC开始映射,所以GIC的假造地点就是PERIPH_DEVICE_BASE:
  1. // kernel/liteos_a/kernel/base/include/los_vm_zone.h
  2. #define GIC_VIRT_BASE    PERIPH_DEVICE_BASE
  3. // vendor/democom/demochip/board/include/asm/platform.h
  4. #define GIC_BASE_ADDR             (GIC_VIRT_BASE)
复制代码


四、启动后测试



        在启动文件中有这样一段
这样启动时串口有打印我们就知道启动乐成了
栈的初始化我们是从0x4000 0000开始的背面的大小是内核的大小liteos-a不会大于16MB
        看过我之前做linux系统移植的兄弟们应该知道之前在4412上运行裸机程序都是在40008000这个地点上,我猜测这个8000可能是uboot的大小,但是背面问了华清的老师这个是武老师的个人喜好,好家伙我直接好家伙。uboot其实不在这运行,在内存运行的话不久死循环了么,因为内存是uboot初始化的哇哈哈。应该是soc内部还有一小段空间可供uboot在启动时使用,或者可能cpu直接去存放uboot的ROM里取的,以上都是猜测背面有机会研究一下这个芯片的启动过程。

        汇编要跳转的测试函数我们放到这个文件里,这里要定义一下串口控制器的位置,其实这里有个问题,就是这个代码不是通用的我们这个等待发送完成要根据本身的芯片手册做偏移。还有这个发送缓冲区的位置,这个通常也是个寄存器地点和这个串口相关的代码大概都在串口的地点做偏移的位置,一样平常会对整个串口的寄存器做个大的布局体。这里由于架构就不对我们只能先意思一下咯。

假造地点加载完在做个打印测试


这里我们前面定义过宏,切记写代码不要魔鬼数字,背面本身都不知道是干嘛的了。
因为对应布局体没实现背面这里肯定会报错的,我就先注释掉了







免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

千千梦丶琪

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表