SylixOS T3 最小系统搭建

全志T3最小系统搭建


  

1. SylixOS最小系统组成

1.1 内核启动流程

2. TICK

3. 串口

3.1 UART 通信格式

3.2 UART寄存器

3.3 驱动实现

3.4 UART驱动框架理解

3.5 最小系统调用接口

4. 最小系统搭建完成

5. 参考资料

 


1. SylixOS最小系统组成

SylixOS 最小系统包含中断、Tick、串口三部分。其中中断为最小系统的任务处理提供基础,允许系统进行任务调度;Tick 是整个最小系统的最小计时单位,为系统的任务处理时间提供参考依据;串口是最小系统中板卡与 PC 端进行通信的基础,用于板卡信息的收发。三个部分的协同作用保证了 SylixOS 最小系统的正常运行。

移植T3bsp最小系统可参考博客:http://www.databusworld.cn/10115.html。博客中的内容可支持达到操作系统通过uboot的串口驱动来打印出调试信息。除此之外,文档偏向与UART驱动框架的讲述。

 

1.1 内核启动流程

内核启动流程在系统移植时是必须掌握的,如 1-1所示。

 

1-1 内核启动流程

1、内核启动初始化入口

这个就是startup.S中做的工作,主要就是一些架构相关的初始化工作。

2、系统基础组件初始化

主核启动时在BSP中会调用API_KernelPrimaryStart 执行内核所有组件的初始化工作。首先会调用_KernelPrimaryLowLevelInit 接口来初始化系统一些基础组件,比如调度器、消息队列、内核堆管理器等等:

3BSP中断控制器初始化

通过调用bspIntInit 接口来初始化中断控制器,这个接口需要在bspLib.c中实现。

4、系统高级组件初始化

调用_KernelHighLevelInit 来初始化系统高级组件,比如信号系统、中断延迟队列、总线系统。

5VMMCache组件初始化

这是在bspInit.c中的usrStartup 函数中做的。

6、创建初始化启动任务

BSP中的大部分驱动初始化、设备创建等等工作都是在halBootThread 这个线程中做的。这个线程同样是在usrStartup 函数中创建,但是要注意的是这时仅仅是创建了这个线程,它并没有被调度运行,在内核所有工作都初始化完成后会调度这个线程进行工作。

7BSP系统TICK初始化

通过调用bspLib.c中的bspTickInit 接口来初始化系统TICK,其实就是初始化一个硬件定时器并让其以系统TICK频率开始工作

8启动内核,调度任务运行

到这里为止,内核的初始化工作哦基本已经完成了,这时就需要选择一个优先级最高的线程来运行了,这是通过调用_KernelPrimaryCoreStartup 来实现的。

9运行初始化启动任务

在这个初始化线程halBootThread 中会去初始化驱动、Posix组件、动态加载器、SylixOS Shell等等一些列的功能,这些初始化的顺序使用默认的即可,一般不需要太大的修改。这里只介绍几个调用到的比较重要的接口

10创建t_main任务运行

这个线程主要就是创建一个SylixOS Shell以让用户可以和SylixOS进行交互

2. TICK

使用时用户设置一个初始值,启动后定时器进行递减,如果减到0则可以产生一个中断。如果用户使用自动重载功能,硬件自动重新从初始值再次开始递,直到再次减到0产生中断,依次往复 2-1所示。

 

2-1 定时器流程图

进行 T3 定时器的驱动实现。驱动相关函数接口如下:

VOID  timerStart (INT32  iNum, UINT32  uiHZ)

{

    UINT32  uiCount;

    UINT32  uiIntvOffset;

    UINT32  uiCtrlOffset;

    if (0 == iNum) {

        uiIntvOffset = TIMER0_INTV;

        uiCtrlOffset = TIMER0_CTRL;

    } else if (1 == iNum) {

        uiIntvOffset = TIMER1_INTV;

        uiCtrlOffset = TIMER1_CTRL;

    } else {

        return ;

    }

    uiCount  = TIMER_FREQ;

    uiCount /= uiHZ;

    writel(uiCount, TIMER_BASE + uiIntvOffset);

    writel(BIT(1) | BIT(2) | BIT(4), TIMER_BASE + uiCtrlOffset);

    while ((readl(TIMER_BASE + uiCtrlOffset) >> 1) & 0x01);

    writel(readl(TIMER_BASE + uiCtrlOffset) | BIT(0), TIMER_BASE + uiCtrlOffset);

    writel(readl(TIMER_BASE + TIMER_IRQ_EN) | BIT(iNum), TIMER_BASE + TIMER_IRQ_EN);

}

VOID  timerIntClear (INT32  iNum)

{

    if ((0 != iNum) && (1 != iNum))

        return ;

    writel(readl(TIMER_BASE + TIMER_IRQ_STA) | BIT(iNum), TIMER_BASE + TIMER_IRQ_STA);

}

BOOL  timerIsIntPending (INT32  iNum)

{

    if ((0 != iNum) && (1 != iNum))

        return  FALSE;

    return  (readl(TIMER_BASE + TIMER_IRQ_STA) & BIT(iNum)) ? TRUE : FALSE;

}           

timerStart:使能定时器,需要将定时器输出的频率作为参数传入。

timerIntClear:清除定时器模块中断状态。

timerIsIntPending:检测定时器模块是否产生了中断。

3. 串口

3.1 UART 通信格式

串口全称叫做串行接口,通常也叫做 COM 接口,串行接口指的是数据一个一个的顺序传输,通信线路简单。使用两条线即可实现双向通信,一条用于发送,一条用于接收。串口通信距离远,但是速度相对会低,串口是一种很常用的工业接口。

UART 作为串口的一种,其工作原理也是将数据一位一位的进行传输,发送和接收各用一条线,因此通过 UART 接口与外界相连最少只需要三条线:TXD(发送)、RXD(接收)和 GND(地 线)。 3-1 就是 UART 的通信格式:

 

3-1 UART 通信格式

中各位的含义如下:

空闲位:数据线在空闲状态的时候为逻辑1”状态,也就是高电平,表示没有数据线空闲,没有数据传输。

起始位:当要传输数据的时候先传输一个逻辑0”,也就是将数据线拉低,表示开始数据传输。

数据位:数据位就是实际要传输的数据,数据位数可选择 5~8 位,我们一般都是按照字节传输数据的,一个字节 8 位,因此数据位通常是 8 位的。低位在前,先传输,高位最后传输。

奇偶校验位:这是对数据中1”的位数进行奇偶校验用的,可以不使用奇偶校验功能。

停止位:数据传输完成标志位,停止位的位数可以选择 1 位、1.5 位或 2 位高电平,一般都选择 1 位停止位。

波特率:波特率就是 UART 数据传输的速率,也就是每秒传输的数据位数,一般选择 960019200115200 等。

3.2 UART寄存器

定时器的接口函数实现主要参考 T3数据手册对相应寄存器的设置,通过对这些寄存器的信息读写操作实现定时器驱动 3-2所示。

Register Name

Offset

Description

UART_RBR

0x0000

接收缓存区寄存器

UART_THR

0x0000

传送保持寄存器

UART_DLL

0x0000

除数锁存寄存器

UART_DLH

0x0004

除数锁存寄存器

UART_IER

0x0004

中断使能寄存器

UART_IIR

0x0008

中断标识寄存器

UART_FCR

0x0008

FIFO控制寄存器

UART_LCR

0x000C

线路控制寄存器

UART_MCR

0x0010

Modem控制寄存器

UART_LSR

0x0014

线路状态寄存器

UART_MSR

0x0018

Modem状态寄存器

UART_SCH

0x001C

Scratch注册

UART_USR

0x007C

状态寄存器

UART_TFL

0x0080

传输FIFO级别

UART_RFL

0x0084

收到FIFO级别

UART_HALT

0x00A1

停止TX寄存器

3-2定时器相关寄存器

程序所需要配置的寄存器也只有RBRTHRDLLDLHIERFCRLCRLSRUSR寄存器。

RBRTHR寄存器:(USR寄存器bit0位为1busy0:空闲)只有UART在空闲状态下设置了LCRbit7DLAB0才可以访问此寄存器,接受和发送数据。

DLLDLH寄存器:(USR寄存器bit0位为1busy0:空闲)只有UART在空闲状态下设置了LCRbit7DLAB1才可以访问此寄存器,设置波特率。

IERbit0来启用接收数据可用中断,bit1来启用传输保持寄存器空中断。

FCRbit0使能FIFO每当该位改变,FIFOXMITRCVR控制寄存器都会重置,bit1 RCVR重置自我清理,bit2 XMIF重置自我清理。

LCR:配置数据位,停止位,奇偶校验,除数锁存寄存器。

LSRbit0 DR数据准备好,bit5 THRE传输保持寄存器为空。

USRbit0 uart busy,传输和发送FIFO是否为满,是否为空。

 

3.3 驱动实现

TTY设备是一个字符设备,对TTY设备的操作流程与普通文件操作流程相似,用SIO_CHAN创建一个TTY设备。

安装TTY设备驱动程序

iosDrvInstall(_ttyOpen,

           (FUNCPTR)LW_NULL,

           _ttyOpen,

           _ttyClose,

           _TyRead,

           _TyWrite,

           _ttyIoctl);             

 

UART 的正常运行主要依靠五个基本功能函数实现:Ioctl 串口控制函数、TxStartup 启动发送函数、CallbackInstall 回调注册函数、PollInput 轮询接收函数、PollOutput 轮询发送函数。这五个函数会在 base 中进行调用以确保 UART 的正常运行。

_TyWrite中:SemBPendrngBufPut_TyTxStartupSemBPost

_TyRead中:SemBPendrngBufGet,SemBPost

_ttyloctl中:sioloctl_Tyloctl

_ttyStartup中:sioTxStartup

 

SIO_DRV_FUNCS按照要求实现5个函数

struct sio_drv_funcs {                                    /*  driver functions            */

    

    INT               (*ioctl)

                      (

                      SIO_CHAN    *pSioChan,

                      INT          cmd,

                      PVOID        arg

                      );

                      

    INT               (*txStartup)

                      (

                      SIO_CHAN    *pSioChan

                      );

                      

    INT               (*callbackInstall)

                      (

                      SIO_CHAN          *pSioChan,

                      INT                callbackType,

                      VX_SIO_CALLBACK    callback,

                      PVOID              callbackArg

                      );

                      

    INT               (*pollInput)

                      (

                      SIO_CHAN    *pSioChan,

                      PCHAR        inChar

                      );

                      

    INT               (*pollOutput)

                      (

                      SIO_CHAN    *pSioChan,

                      CHAR         outChar

                      );

};

CallbackInstall:回调实现接口。

Poll接口:轮询收发接口实现。

sio16c550isr:收发中断接口。

TxStartup:启动发送接口。

3.4 UART驱动框架理解

进行最小系统移植起初会进行bspBoardDebugMsg打印调试信息,此时操作系统通过uboot的串口驱动来打印出调试信息,使用的是直接向THR寄存器写入数据。

在进行uart驱动框架的搭建,操作系统是通过TTY设备来访问UART驱动的,集可进行openreadwritecloseioctl。开发者在编写UART驱动只需要将sio_drv_funcs结构体的函数实现就可以被tty设备调用。

app向串口发送数据大致流程为:appbuffer传给tty设备的buffertty设备的buffer再向寄存器写入。

串口向app发送数据大致流程为:串口将数据传给tty设备的buffertty设备的buffer再传给app

3.5 最小系统调用接口

T3 最小系统中的 UART 驱动调用主要体现在 bsp 多任务状态下的初始化启动任务中创建了一个 SylixOS 可识别的 tty 字符终端设备。主要过程为在 bsp/bspInit.c  halDevInit函数初始化目标系统静态设备组件时创建一个UART 通道,然后调用内核接口函数添加相应 tty 设备,具体设置如下:

    SIO_CHAN    *psio;                                          /*  内核可识别通道 */

 

#if  UART0_EN > 0

    psio = sioChanCreate(0);                                         /*  创建串口0 通道*/

    if (psio) {

        ttyDevCreate("/dev/ttyS0", psio, 256, 256);                      /*  增加 tty 设备   */

    }

#endif

注:

为避免 T3 最小系统的板卡驱动初始化的更改影响 bsp 的整体运行,将板级设备初始化单独封装成 bspBoardDevInit 函数便于驱动的删改;

为便于不同 UART 的管理,本例中将不同 UART 的使能进行了宏定义;

由于在目标板卡上未将 UART1  UART6对应引脚引出,所以本例中未将 UART1 UART6 进行初始化。

4. 最小系统搭建完成

全志 T3 板卡最小系统搭建完毕后应能正常启动 SylixOS 终端,在屏幕上打印 SylixOS 标志及 bsp 基本信息,且能正常使用 tshell 风格命令,同时每次调tshell 命令后相对应的 UART 中断及 Tick 中断都应当增加,如 4-1所示。至此全志 T3 板卡 SylixOS 最小系统搭建完毕,中断、Tick 和串口驱动运行正常。

 

4-1SylixOS 最小系统运行

注:

图示为避免 Uboot 串口初始化影响串口驱动正常运行与否判断,已将系统标准入输出文件设置为 “/dev/ttyS7”,即 UART7。此时 UART7 能正常显示信息并产生中断,证明串口驱动编写无误,需将系统标准输入输出文件改为默认 “/dev/ttyS0”

5. 参考资料

SylixOS设备驱动程序开发》

全志 T3 Linux 源码

Base 16c550源码

博客:http://www.databusworld.cn/10202.html



    • Related Articles

    • 在 SylixOS INT8 类型是否带有符号

      Q:在 SylixOS INT8 类型是否带有符号 INT8 类型在 BSP 中定义, SylixOS 要求 INT8 型为有符号 8 位整形, 有些编译器默认 char 为无符号数, 所以在 BSP 中定要将 INT8 定义为 signed char 型.  (int8_t 类型由 INT8 定义, C99 中要求 int8_t 为有符号数)INT8 类型在 BSP 中定义, SylixOS 要求 INT8 型为有符号 8 位整形, 有些编译器默认 char 为无符号数, 所以在 ...
    • 全志芯片显示系统简介

      压缩包内容:主要对全志T系列芯片的显示模块软硬件做一个基本介绍,总的来说,全志的显示系统还是有点复杂的。 DE2.0的数据手册及其介绍见 附件压缩包。
    • 全志芯片显示系统简介

            主要对全志T系列芯片的显示模块软硬件做一个基本介绍,详情见附件。
    • cpuus 命令

      说明 该命令用于查看cpu利用率 格式 cpuus [-n times] [-t wait_seconds] -n:检测cpu利用率的次数 -t:每次检测用的时间 wait_seconds:每次检测的时间是 wait_seconds 秒 可通过shell命令:help cpuus 查看详细信息 示例 1.查看cpu利用率 [root@sylixos:/apps]# cpuus CPU usage checking, please wait... CPU usage show ...
    • SylixOS 挂载 RAM 文件系统

      mount -t ramfs 【空间大小(字节)】  【挂载位置】 # mount -t ramfs 10000000 /mnt/ram 注意:此空间从内核堆中分配,若需要较大的空间需要适当扩大内核堆空间。或者是在 Base 配置文件中开启如下宏定义。 #define LW_CFG_RAMFS_VMM_EN                 0                           /*  是否使用 VMM 开辟内存       */