zoukankan      html  css  js  c++  java
  • Hello China操作系统STM32移植指南(二)

    移植步骤详解

    下面就以MDK 4.72为开发环境,详细说明Hello China内核向STM32的移植过程。MDK 4.72评估版只支持32K代码的编译,这对Hello China的内核来说,裁剪掉一些非核心功能,也足够了。如果您希望体验更多功能,请使用非评估版。您可以花钱买,也可以通过其它途径获得,具体不细说,你懂的。

    首先建立一个新的项目,注意要指定一个项目所在目录,并选择合适的STM32芯片。我选择的是STM32F103R8,如下图:

     

    点击OK后,MDK会提示是否拷贝startup_stm32f10x_md.S到项目中,选择“是”。这样MDK会自动生成一个启动文件,到所选目录下。

    假设项目所在的目录是HXOS03,则进入该目录,创建下列几个文件夹:


    其中HXOS存放Hello China操作系统源文件,Obj&Lst存放MDK编译生成的过程和目标文件,Startup存放启动文件(把上图中startup_stm32f10x_md.s拷贝到Startup文件夹),User则存放用户应用程序源文件。

    然后把Hello China V1.76的源文件拷贝到HXOS目录下。下面是拷贝之后的结构(HXOS目录下所包含的文件夹):


    其中有几个文件夹,在STM32下是不需要的,可以把它删除掉。主要有fs/shell两个目录。其中fs存放的是文件系统代码,我们的移植目标板上没有存储系统,故不需要该文件夹内容。Shell是面向PC的一个命令行界面,在STM32下也不需要。

    再进入MDK,建立与上述目录基本对应的文件夹架构,如下图:


    然后把文件夹中的文件,逐一添加到项目中。需要注意的是,MDK只支持二级目录,即不能继续在HXOS目录下再创建子目录。由于HXOS存放的是Hello China源代码,分好几个子目录存放,因此在添加到项目中的时候,实际目录结构就消失了,所有文件都统一显示在MDK的HXOS目录下。这有点不方便,主要是寻找某个文件的时候,但好消息是,操作系统内核需要修改的地方不多,而且一劳永逸,这个不方便也可以克服。

    完成文件的添加后,在MDK中对项目做一些配置。打开项目选项对话框(为了简便,就不贴图了。MDK中按下ALT+F7键,即可看到),主要有以下几点设置:

    1.         把编译生成的中间和目标文件,以及list文件,存放到创建的Obj&Lst目录下。选择对话框中的output和listing选项,分别点击“select folder for objects…”和“select folder for listings…”,即可设置;

    2.         选择项目选项对话框中的“C/C++“页签,在”Define“编辑框中,输入”STM32F10X_MD“。这是一个预定义宏,告诉编译器,我们的目标STM32平台是中等密度的(因为我们选择的目标是STM32F103RB)。至于什么是STM32 MD,HD,LD等,请参阅相关资料;

    配置完成后,点击OK。

    接下来,需要修改几个地方的代码,主要有:

    1.        启动文件中,需要增加链接中断的代码。打开startup_stm32f10x_md.s文件,找到下列代码:

    ………

    USART1_IRQHandler

    USART2_IRQHandler

    USART3_IRQHandler

    EXTI15_10_IRQHandler

    RTCAlarm_IRQHandler

    USBWakeUp_IRQHandler

                    B       .

                    ENDP

                    ALIGN

    把上述代码中的“B .“一行删除,修改为下列代码(斜体部分):

    ………

    EXTI15_10_IRQHandler

    RTCAlarm_IRQHandler

    USBWakeUp_IRQHandler

                    IMPORT Int_Entry_Wrapper

                    LDR R0,=Int_Entry_Wrapper

                    BX R0

                    ENDP

                    ALIGN

    这样就实现了硬件中断和Hello China操作系统中断机制的链接。

    2. 内存配置。找到HXOS目录下的mem_scat.c文件,找到下列代码:

    __MEMORY_REGION SystemMemRegion[] = {

         {(LPVOID)KMEM_ANYSIZE_START_ADDRESS,0x00100000},

         {(LPVOID)(KMEM_ANYSIZE_START_ADDRESS+ 0x00100000),0x00100000},

         {(LPVOID)(KMEM_ANYSIZE_START_ADDRESS+ 0x00200000),0x00100000},

         {(LPVOID)(KMEM_ANYSIZE_START_ADDRESS+ 0x00300000),0x00100000},

         //Please add more memoryregions here.

         //The last entry must beNULL and zero,to indicate the end of this array.

         {NULL,0}

    };

    修改为下列内容:

    __MEMORY_REGION SystemMemRegion[] = {

         {(LPVOID)0x20003000,0x00002000},

         //Please add more memoryregions here.

         //The last entry must beNULL and zero,to indicate the end of this array.

         {NULL,0}

    };

    这告诉操作系统的内存管理机制,空闲内存是从0x20003000开始,长度是8K。这里直接使用了固定编码的方式,告诉操作系统空闲内存起始地址。这种处理方式是不合适的,因为如何确定空闲内存起始地址,是个问题。这里的0x20003000是通过分析编译输出的map文件,推算出来的。但是要实现自动的空闲内存设定,则需要修改编译器的散列文件(sct文件),比较复杂。因此暂时先用这种方式替代。如有复杂的场景,再考虑修改sct文件来实现空闲内存的自动界定。如果读者朋友有更好的方法,也欢迎反馈。

    3. 接下来是最后一步,就是修改config.h文件。这是操作系统的核心配置文件,相关功能模块都在这个文件中进行配置。具体来说,注释掉某些宏定义,并打开针对STM32的一些宏定义。下列是修改之后,该文件的大致内容(删除了注释):

    #define __CONFIG_H__ //Include switch.

    #define __CFG_CPU_LE

    //CPU types,the following definitions are exclusive.

    //#define __I386__

    //#define __ARM7__

    //#define __ARM9__

    //#define __ARM11__

    #define __STM32__

    #define SYSTEM_TIME_SLICE  50

    #define MIN_STACK_SIZE 128

    #define MAX_INTERRUPT_VECTOR 128

    #define DEFAULT_STACK_SIZE 0x00000400 //1k space for kernel threadstack.

    //#define __CFG_SYS_IS

    //#define __CFG_SYS_VMM

    //#define __CFG_SYS_BM

    #define __CFG_SYS_MMFBL

    //#define __CFG_SYS_MMTFA

    #define __CFG_SYS_DDF

    //Include CPU statistics functions in OS.

    //#define __CFG_SYS_CPUSTAT

    //#define __CFG_SYS_SHELL

    //#define __CFG_SYS_CONSOLE

    //#define __CFG_DRV_IDE

    //#define __CFG_DRV_COM

    //Include USART driver in OS,specific for STM32 or ARM platform.

    #define __CFG_DRV_USART

    //#define __CFG_DRV_MOUSE

    //#define __CFG_DRV_KEYBOARD

    //#define __CFG_FS_FAT32

    //#define __CFG_FS_NTFS

    //#define __CFG_FS_RAM

    //#define __CFG_FS_FLASH

    //#define __CFG_NET_IPV4

    //#define __CFG_NET_IPV6

    #define __CFG_USE_EOS

    //User entry point thread's priority if used as EOS.

    #define __HCNMAIN_PRIORITY PRIORITY_LEVEL_NORMAL

    //User entry point thread's name.

    #define __HCNMAIN_NAME     "HCN_Main"

    从中可以看出Hello China操作系统的裁剪配置思路。只要把对应的宏定义打开,相应的功能就包含在Hello China内核里面了。注释掉之后,相应的功能就被裁剪掉,内核尺寸就会变小。

    完成上述所有修改和配置之后,直接在MDK中按F7键,即可编译链接了。会有一些告警提示,忽略即可。如无意外,应该会编译成功,生成目标文件。

    这时候,可以使用MDK内置的模拟器进行调试。由于我们实现了USART1的驱动程序,也随之实现了一个简单的交互界面(在user文件夹下的usermain.c文件中),因此如果用串口链接STM32的USART1接口,输入“m”,即可看到内存使用情况的统计输出。

    下面介绍一个简单的调试方法。在进入调试状态后(选择“debug”菜单,选择“start/stop debug session”选项),在MDK左下角弹出的command窗口中,输入下列命令:

    mode com3 115200,0,8,1

    assign com3 <s1in> s1out

    如下图:


    即可把PC机的COM3接口与MDK所虚拟的STM32的USART1链接起来(波特率是115200,无校验,8位数据位,1位停止位)。

    这时候使用诸如VSPD等串口虚拟软件,把COM3(链接了STM32的USART1)和COM4环接起来,则使用诸如超级终端等串口软件(指定COM4串口,并配置与COM3相同的参数),即可与STM32虚拟机交互了。下图是交互的输出:

     

    用户编程模型

    Hello China在初始化完成之后,如果发现定义了__CFG_USE_EOS宏,则试图创建一个核心线程,入口函数名称是_HCNMain。用户应用程序代码需要在这个函数中实现。因此,在成功移植Hello China之后,用户需要在user目录下,创建自己的源文件,并实现_HCNMain函数。这个函数与缺省的main函数一样,是用户功能代码的入口。在_HCNMain函数中,用户可以调用Hello China提供的一系列系统服务,比如创建核心线程,申请/释放内存,读写文件等。下面是系统附带的一个实现,这个实现很简单,就是不断读取USART1的输入,并回显出来。如果发现输入是“m”,则调用ShowMemory函数,输出内存分配情况。

    下面是_HCNMain函数的源代码,贴到这里供参考。如果用户想实现自己的独特功能,可以直接修改_HCNMain函数:

    DWORD _HCNMain(LPVOID pData)

    {

         __COMMON_OBJECT* hUsart =NULL;

         DWORD           dwWriteLen = 0;

         CHAR            chCmd;

         CHAR            strInfo[64];

         hUsart =IOManager.CreateFile(

             (__COMMON_OBJECT*)&IOManager,

             "\\.\USART1",

             0,

             0,

             NULL);

         if(NULL == hUsart)

         {

               SER_PutString("_HCNMain:Can not open USART object. ");

               return 0;

         }

         SER_PutString("_HCNMain:Open device USART successfully. ");

         while(TRUE)

         {

               if(IOManager.ReadFile(

                     (__COMMON_OBJECT*)&IOManager,

                 hUsart,

                 1,

                 &chCmd,

                 NULL))

               {

                     IOManager.WriteFile(

                   (__COMMON_OBJECT*)&IOManager,

                   hUsart,

                   1,

                   &chCmd,

                   &dwWriteLen);

                     if('m' ==chCmd)

                     {

                          ShowMemory(hUsart);

                     }

               }

         }

         //return 1;

    }

    从上述代码中可以看出,_HCNMain可以调用Hello China操作系统的API,来实现相应功能。对物理设备的操作也大大简化,所有设备,都是按照文件的操作接口来统一操作。这样的好处是,不用关心底层的驱动程序实现,只需要聚焦应用的实现即可。这种模式适合大型软件的开发,可以把整个任务分为两个部分:驱动代码和应用代码,并分别由不同的团队承接,相互不干扰,有利于提升开发效率。

    其它相关问题的说明

    接下来,对操作系统移植过程中的其它相关问题做一番说明。首先是CPU复位后的执行入口点问题。在startup文件中,MDK定义了一个入口点函数Reset_Handler,Hello China的实现方式是,在osadapt.s中重新定义一个Reset_Handler函数,替代MDK定义的这个。因为MDK在定义的时候,使用了[weak]修饰,因此只要在osadapt.S中定义的Reset_Handler不使用weak修饰即可。这样CPU复位后,将跳转到osadapt.S文件定义的Reset_Handler处开始执行。这时候会首先调用SystemInit函数,这个函数是一个缺省实现,从MDK开发环境附带的例子(位于KeilARMExamples目录下)中拷贝过来的。SystemInit函数完成系统时钟的配置等工作,然后再跳转到MDK定义的__main函数。这个函数内嵌了一些全局数据重定位代码,把全局变量搬迁到0x200000000开始处(即RAM开始处),然后再调用main函数。Main函数在os_Entry.c文件中实现,调用了操作系统初始化函数_OS_Entry。_OS_Entry完成Hello China操作系统的初始化,并创建用户线程_HCNMain。_HCNMain得到调度的时候,就正式进入用户程序了。需要说明的是,在main函数中,调用_OS_Entry之前,首先对Systick进行了初始化,这是产生系统tick的机制。

    USART驱动程序在Hello China初始化过程中被加载。驱动程序首先初始化USART1相关的控制器,开启USART1功能,然后调用ConnectInterrupt函数,把USART1的中断处理函数链接到Hello China的中断处理机制。这样USART1就可以被用户程序通过文件API访问了。具体例子,可参考上述_HCNMain的实现案例。

    通过合适的裁剪,可以把Hello China的内核大小控制在10~20K之间。当然,如果进一步增加其它功能,比如FS,网络,shell,则内核尺寸会超过40K。如果进一步增加GUI,则需要额外内存支持了。

    最后,再把Hello China的扩展机制总结一下,因为Hello China的应用目标是物联网操作系统,需要面对各种规格的硬件配置,因此操作系统的伸缩性是非常关键的。Hello China的伸缩性,大致表现在下列方面:

    1.   内核线程的数量无限制,可以随便创建,仅受限于物理内存大小;

    2.   采用统一的文件API,访问文件和设备。这样可以把用户功能代码和底层的硬件驱动程序隔离开,方便大型软件的开发;

    3.   采用链式中断机制,对中断的数量无限制,而且可以动态添加和删除中断处理程序;

    4.   内嵌灵活扩展的驱动程序管理框架,要增加驱动程序,只需要按照Hello China的驱动程序框架编写代码,然后在驱动程序加载列表中注册一项即可。操作系统在初始化过程中,会加载驱动程序加载列表中的所有驱动程序;

    5.   内存管理机制灵活,可以在mem_scat.c文件中添加多个内存块,比如外部RAM等,实现统一管理;

    6.   实现统一的文件系统框架,用户通过统一的API接口访问文件,不管文件的底层存储格式是什么。同时,文件系统可动态添加或删除。在动态添加存储设备的时候,文件系统会得到通知,如果是可识别的文件系统,会实时挂接到系统中,呈现给用户。这种机制十分适合外设丰富的应用场景。

          总之,通过添加驱动程序,核心线程,文件系统/GUI/网络功能等模块,可以快速扩展HelloChina的功能,而且这种功能对用户来说是完全透明的。相反,通过裁减不需要的功能,也可以把Hello China的尺寸控制在很小的范围(小于10K)。这样一种可伸缩性的特征,符合物联网操作系统多样化的需求。

    欢迎对物联网操作系统感兴趣的同仁投入,继续开发。物联网已经被广泛看好,支撑物联网发展的操作系统,必定会越来越受到重视。对参与者个人来说,物联网操作系统正处于开发的初始阶段,这个时候参与进来,持续跟进甚至主导,逐渐积累,在该领域成为权威,会比其它领域更加容易,效果也会更好。物联网操作系统给所有系统软件爱好者提供了一个难得的机会,真诚希望我们都能够抓住。

    同时也欢迎物联网领域的企业或单位,能够应用Hello China操作系统。我们会提供更加周到的服务。

    任何问题,请联系:

    QQ/微信:89007638

    Email:garryxin@gmail.com

  • 相关阅读:
    【BZOJ 2124】【CodeVS 1283】等差子序列
    【BZOJ 1036】【ZJOI 2008】树的统计Count
    【BZOJ 1901】【ZJU 2112】Dynamic Rankings
    【BZOJ 3924】【ZJOI 2015】幻想乡战略游戏
    【BZOJ 4103】【THUSC 2015】异或运算
    【BZOJ 4513】【SDOI 2016】储能表
    【HDU 3622】Bomb Game
    【BZOJ 3166】【HEOI 2013】Alo
    【BZOJ 3530】【SDOI 2014】数数
    【BZOJ 4567】【SCOI 2016】背单词
  • 原文地址:https://www.cnblogs.com/fengju/p/6174200.html
Copyright © 2011-2022 走看看