打印
[牛人杂谈]

NUC970(ARM9) UCOSIII移植

[复制链接]
1418|7
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
zljiu|  楼主 | 2021-6-6 10:32 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
ARM9 与 A7移植差不多,都比STM32简单,区别在于ARM9开关中断不一样,一些新指令不支持,并且NUC970没有VFP,无法使用硬件浮点运算,因此无需保存S0-S31这些寄存器,堆栈消耗也会少一些。

//在.S文件中使用UCOS提供的中断管理

startus.s


        ;/***************************************************************************
    ; *                                                                         *
    ; * Copyright (c) 2020 NUC970裸机启动文件.             *
    ; *                                                                         *
    ; ***************************************************************************/
    ;
VFPEnable                           EQU        (0x40000000) ;VFP使能设置

;为用户堆预留空间
Heap_Size               EQU     (512*1024)                                        ;堆大小
                                        AREA    HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base               
Heap_Mem                SPACE   Heap_Size
__heap_limit


       
;用户模式堆栈大小位所有堆栈预留空间
USR_Stack_Size                EQU                1024                                                                ;用户模式堆栈大小
OTH_Stack_Size                EQU                256                                                                        ;其他模式堆栈大小                       
                                        AREA    STACK, NOINIT, READWRITE, ALIGN=3        ;堆栈设置为8字节对齐
UND_Stack_Mem       SPACE   OTH_Stack_Size
Abort_Stack_Mem     SPACE   OTH_Stack_Size
FIQ_Stack_Mem       SPACE   OTH_Stack_Size
IRQ_Stack_Mem       SPACE   OTH_Stack_Size
SVC_Stack_Mem       SPACE   OTH_Stack_Size
USR_Stack_Mem       SPACE   USR_Stack_Size        
__initial_sp       

        PRESERVE8
    AREA NUC_INIT, CODE, READONLY

;--------------------------------------------
; Mode bits and interrupt flag (I&F) defines
;--------------------------------------------
USR_MODE    EQU     0x10
FIQ_MODE    EQU     0x11
IRQ_MODE    EQU     0x12
SVC_MODE    EQU     0x13
ABT_MODE    EQU     0x17
UDF_MODE    EQU     0x1B
SYS_MODE    EQU     0x1F

I_BIT       EQU     0x80
F_BIT       EQU     0x40
       


    ENTRY
                EXPORT  Reset_Go
                IMPORT  OS_CPU_ARM_ExceptUndefInstrHndlr               
        IMPORT  OS_CPU_ARM_ExceptSwiHndlr                     
        IMPORT  OS_CPU_ARM_ExceptPrefetchAbortHndlr
        IMPORT  OS_CPU_ARM_ExceptDataAbortHndlr
        IMPORT  OS_CPU_ARM_ExceptIrqHndlr
        IMPORT  OS_CPU_ARM_ExceptFiqHndlr       

        EXPORT  Vector_Table
Vector_Table
        B       Reset_Go    ; Modified to be relative jumb for external boot
        LDR     PC, Undefined_Addr
        LDR     PC, SWI_Addr
        LDR     PC, Prefetch_Addr
        LDR     PC, Abort_Addr
        DCD     0x0
        LDR     PC, IRQ_Addr
        LDR     PC, FIQ_Addr


Reset_Addr      DCD     Reset_Go
Undefined_Addr  DCD     OS_CPU_ARM_ExceptUndefInstrHndlr;            ;未定义指令异常
SWI_Addr        DCD     OS_CPU_ARM_ExceptSwiHndlr                    ;软件中断,管理模式
Prefetch_Addr   DCD     OS_CPU_ARM_ExceptPrefetchAbortHndlr          ;中止预取模式
Abort_Addr      DCD     OS_CPU_ARM_ExceptDataAbortHndlr              ;中止数据模式
                DCD     0
IRQ_Addr        DCD     OS_CPU_ARM_ExceptIrqHndlr                    ;中断模式
FIQ_Addr        DCD     OS_CPU_ARM_ExceptFiqHndlr                    ;快速中断模式


        ; ************************
        ; Exception Handlers
        ; ************************

Reset_Go

        ;关闭中断
        MRS         R0,         CPSR                       ;读取CPSR的值
        ORR         R0,         R0,         #0x80        ;将IRQ中断禁止位I置1,即屏蔽IRQ中断
        MSR         CPSR_c, R0                                ;设置CPSR的值

    ;--------------------------------
    ; Initial Stack Pointer register
    ;--------------------------------
    ;INIT_STACK
        MSR    CPSR_c, #UDF_MODE :OR: I_BIT :OR: F_BIT
        LDR    SP, =(UND_Stack_Mem+OTH_Stack_Size)

        MSR    CPSR_c, #ABT_MODE :OR: I_BIT :OR: F_BIT
        LDR    SP, =(Abort_Stack_Mem+OTH_Stack_Size)

        MSR    CPSR_c, #IRQ_MODE :OR: I_BIT :OR: F_BIT
        LDR    SP, =(IRQ_Stack_Mem+OTH_Stack_Size)

        MSR    CPSR_c, #FIQ_MODE :OR: I_BIT :OR: F_BIT
        LDR    SP, =(FIQ_Stack_Mem+OTH_Stack_Size)

        MSR    CPSR_c, #SVC_MODE :OR: I_BIT :OR: F_BIT
        LDR    SP, =(SVC_Stack_Mem+OTH_Stack_Size)

        MSR    CPSR_c, #SYS_MODE :OR: I_BIT :OR: F_BIT
        LDR    SP, =(USR_Stack_Mem+USR_Stack_Size)


; Reset SCTLR Settings
        MRC     p15, 0, R0, c1, c0, 0     ; Read CP15 System Control register
;        BIC     R0,  R0, #(0x1 << 12)     ; Clear I bit 12 to disable I Cache        当数据cache与指令cache是分开的,此处关闭指令cache
        ORR     R0,  R0, #(0x1 << 12)     ; 开启指令cache
        BIC     R0,  R0, #(0x1 << 13)     ; Clear V bit 13 选择低端异常中断向量 0x0~0x1c
;        BIC     R0,  R0, #(0x1 <<  2)     ; Clear C bit  2 to disable D Cache        关闭数据cache
        ORR     R0,  R0, #(0x1 <<  2)     ; 开启数据cache
;        BIC     R0,  R0, #0x2             ; Clear A bit  1 to disable strict alignment 关闭地址对齐检查
;        BIC     R0,  R0, #(0x1 << 11)     ; Clear Z bit 11 to disable branch prediction 关闭跳转分支预测
        ORR     R0,  R0, #(0x1 << 11)     ; 开启跳转分支预测
        BIC     R0,  R0, #0x1             ; Clear M bit  0 to disable MMU 关闭MMU
        MCR     p15, 0, R0, c1, c0, 0     ; Write value back to CP15 System Control register

               
        ;初始化中断向量表位置
    ;LDR R0, =Vector_Table;
    ;MCR     p15, 0, R0, c12, c0, 0;//设置VBAR

        ;开启系统总中断=>在进入系统前请不要开启中断
;        MRS R0,                CPSR                       ;读取CPSR的值
;    BIC R0,                R0,                #0x80         ;将IRQ中断禁止位I清零,即允许IRQ中断
;    MSR CPSR_c,        R0                            ;设置CPSR的值

        IMPORT  __main
        ;-----------------------------
        ;   enter the C code
        ;-----------------------------
        B   __main

AbortHndlr               
        MSR    CPSR_c, #SVC_MODE :OR: I_BIT :OR: F_BIT
         B       Reset_Go
       

                ;用户堆初始化,如果不初始化为出现异常
                EXPORT  __user_initial_stackheap
__user_initial_stackheap

                 LDR     R0, =  Heap_Mem                                                        ;r0 中的堆基址
                 LDR     R1, = (USR_Stack_Mem + USR_Stack_Size)                ;r1 中的堆栈基址,即堆栈区中的最高地址
                 LDR     R2, = (Heap_Mem +  Heap_Size)                                ;r2 中的堆限制
                 LDR     R3, = UND_Stack_Mem                                                ;r3 中的堆栈限制,即堆栈区中的最低地址。
                 BX      LR

                 ALIGN



    END



使用特权

评论回复
沙发
zljiu|  楼主 | 2021-6-6 10:32 | 只看该作者
然后实现一个用户中断管理接口

/*************************************************************************************************************************
* 函数                        :        void OS_CPU_ExceptHndlr(u32 os_cpu_except)
* 功能                        :        系统中断处理(有操作系统接口)
* 参数                        :        os_cpu_except:中断类型
* 返回                        :        无
* 依赖                        :        操作系统获取到中断后调用此接口,并将中断类型写入到寄存器R0,如果是快速中断或中断,需要自己读取IAR值获取中断编号,
                      执行结束后告知GIC中断处理完毕
* 作者                        :        cp1300@139.com
* 时间                        :        2020-08-21
* 最后修改时间         :         2020-08-21
* 说明                        :        中断类型在os_cpu_a.asm os_cpu.h 中进行了定义,会直接在os_cpu_a.s中调用  
                        OS_CPU_ARM_EXCEPT_RESET           EQU  0x00
                        OS_CPU_ARM_EXCEPT_UNDEF_INSTR     EQU  0x01
                        OS_CPU_ARM_EXCEPT_SWI             EQU  0x02
                        OS_CPU_ARM_EXCEPT_PREFETCH_ABORT  EQU  0x03
                        OS_CPU_ARM_EXCEPT_DATA_ABORT      EQU  0x04
                        OS_CPU_ARM_EXCEPT_ADDR_ABORT      EQU  0x05
                        OS_CPU_ARM_EXCEPT_IRQ             EQU  0x06
                        OS_CPU_ARM_EXCEPT_FIQ             EQU  0x07
*************************************************************************************************************************/
void OS_CPU_ExceptHndlr(u32 os_cpu_except)
{
    switch(os_cpu_except)
    {
        case OS_CPU_ARM_EXCEPT_RESET: //复位
        {

        }break;
        case OS_CPU_ARM_EXCEPT_UNDEF_INSTR:   //未知
        {

        }break;
        case OS_CPU_ARM_EXCEPT_SWI:   //软件切换
        {

        }break;
        case OS_CPU_ARM_EXCEPT_PREFETCH_ABORT://指令中止
        {

        }break;
        case OS_CPU_ARM_EXCEPT_DATA_ABORT:    //数据中止
        {

        }break;
        case OS_CPU_ARM_EXCEPT_ADDR_ABORT:    //地址错误
        {

        }break;
        case OS_CPU_ARM_EXCEPT_IRQ:           //普通中断
        case OS_CPU_ARM_EXCEPT_FIQ:           //快速中断
        {
            u32 mISNR;       
                        u32 intNum;

                        mISNR = AIC->IPER;        //需要先读取IPER,否则ISNR可能没更新,IPER的值>>2位是等于ISNR的,必须先读取IPRE
                        mISNR >>= 2;
                        //mISNR = AIC->ISNR;        //这个寄存器只能读取一次,下次读取会被清零的,ISNR有时候没有及时更新
                        intNum = mISNR & 0X3F;
                        if ((intNum == 0) || (intNum>=NUMBER_OF_INT_VECTORS))   
                        {
                                AIC->EOSCR = 1;        //写入任何值,告诉AIC中断执行完毕了
                                return;
                        }
                        //执行中断服务程序
                        ((void (*)(void)) sg_IRQHandlerTable[intNum])();     //执行中断服务程序
                        AIC->EOSCR = 1;                //写入任何值,告诉AIC中断执行完毕了
        }break;
        default:break;
    }
}


使用特权

评论回复
板凳
zljiu|  楼主 | 2021-6-6 10:33 | 只看该作者
//初始化OS滴答时钟,1ms,并在中断中调用 OSTimeTick();  即可


/*************************************************************************************************************************
* 函数                        :        void OS_Tack_Time2_IRQHandler(void)
* 功能                        :        定时器2中断服务程序,用于OS滴答时钟
* 参数                        :        无
* 返回                        :        无
* 依赖                        :        底层与OS
* 作者                        :        cp1300@139.com
* 时间                        :        2020-08-21
* 最后修改时间         :         2020-08-21
* 说明                        :        中断服务程序是由ucos中断服务程序先进行了处理,此处只需要调用OSTimeTick()并清除中断源即可
*************************************************************************************************************************/
void __inline OS_Tack_Time_IRQHandler(void)
{
    OSTimeTick();        //Call uC/OS-II's OSTimeTick()
}


/*************************************************************************************************************************
* 函数                        :        void SYS_OS_TickInit(void)
* 功能                        :        系统OS滴答时钟初始化(使用的TIM2)
* 参数                        :        无
* 返回                        :        无
* 依赖                        :        底层与OS
* 作者                        :        cp1300@139.com
* 时间                        :        2020-08-21
* 最后修改时间         :         2020-08-21
* 说明                        :        使用定时器2作为时钟源,1ms触发一次中断,用于ucosiii时钟源
*************************************************************************************************************************/
void SYS_OS_TickInit(void)
{
    TIMER_CONFIG mTimConfig;
       
        //定时器测试
        mTimConfig.ComparedValue = 1000;                                                //比较值
        mTimConfig.mode = TIMER_MODE_PERIODIC;                                        //工作模式-周期
        mTimConfig.pIntCallBack = OS_Tack_Time_IRQHandler;                //中断回调函数
        mTimConfig.isStart = TRUE;                                                                //是否开始计数
        mTimConfig.ClockPre = 12-1;                                                                //时钟预分配,分频值=设置值+1,比如设置为1,则为2分频
        mTimConfig.isEnableInt = TRUE;                                                        //是否使能定时器中断
        mTimConfig.IntPro = SYS_INT_OS_TICK_PRO;                                //中断优先级
        TIMERx_Config(SYS_OS_TICK_TIME_CH, &mTimConfig);                //定时器配置
}


使用特权

评论回复
地板
zljiu|  楼主 | 2021-6-6 10:34 | 只看该作者
//OS初始化以及任务建立


//任务堆栈大小定义
#define SYSTEM_STK_SIZE                 (256)                //系统主进程
#define LED_STK_SIZE                (128)                //LED


//任务堆栈声明-建议OS堆栈使用8字节对齐,否则使用64位数打印时会出现各种问题
__align(8) static CPU_STK         TASK_SYSTEM_STK[SYSTEM_STK_SIZE];                    //系统主线程
__align(8) static CPU_STK        TASK_LED_STK[LED_STK_SIZE];                                                //LED线程

//任务控制块
OS_TCB SYSTEM_Task_TCB;
OS_TCB LED_Task_TCB;

//任务列表
void TaskSystem(void *pdata);                                                //任务:系统主线程
void TaskLED(void *pdata);                                                        //任务:LED线程




//OS初始化,它是第一个运行的函数,初始化各种的全局变量,例如中断嵌套计数器、优先级、存储器
    OSInit(&err);
    //创建任务1
    OSTaskCreate(    (OS_TCB *)&SYSTEM_Task_TCB,                                //任务控制块
                    (CPU_CHAR *)"Task1",                                        //任务的名字
                    (OS_TASK_PTR)TaskSystem,                                    //任务函数
                    (void *)0,                                                  //传递参数
                    (OS_PRIO)3,                                                 //任务的优先级        
                    (CPU_STK *)TASK_SYSTEM_STK,                                 //任务堆栈基地址
                    (CPU_STK_SIZE)SYSTEM_STK_SIZE/10,                           //任务堆栈深度限位,用到这个位置,任务不能再继续使用
                    (CPU_STK_SIZE)SYSTEM_STK_SIZE,                              //任务堆栈大小            
                    (OS_MSG_QTY)0,                                              //禁止任务消息队列
                    (OS_TICK)0,                                                 //默认时间片长度                                                               
                    (void  *)0,                                                 //不需要补充用户存储区
                    (OS_OPT)OS_OPT_TASK_NONE,                                   //没有任何选项
                    &err                                                        //返回的错误码
                );


    SYS_OS_TickInit();   
    SYS_EnableIrq();                                                                    //CPU总中断开启
    //启动OS,进行任务调度
    OSStart(&err);


//任务1:系统任务
void TaskSystem(void *pdata)
{
        OS_ERR err;
       
        OS_BoardInit();
       
        //创建任务2
    OSTaskCreate(    (OS_TCB *)&LED_Task_TCB,                                        //任务控制块
                    (CPU_CHAR *)"Task2",                                        //任务的名字
                    (OS_TASK_PTR)TaskLED,                                            //任务函数
                    (void *)0,                                                  //传递参数
                    (OS_PRIO)5,                                                 //任务的优先级        
                    (CPU_STK *)TASK_LED_STK,                                         //任务堆栈基地址
                    (CPU_STK_SIZE)TASK_LED_STK/10,                                   //任务堆栈深度限位,用到这个位置,任务不能再继续使用
                    (CPU_STK_SIZE)TASK_LED_STK,                                      //任务堆栈大小            
                    (OS_MSG_QTY)0,                                              //禁止任务消息队列
                    (OS_TICK)0,                                                 //默认时间片长度                                                               
                    (void  *)0,                                                 //不需要补充用户存储区
                    (OS_OPT)OS_OPT_TASK_NONE,                                   //没有任何选项
                    &err                                                        //返回的错误码
                );


        while(1)
        {       
                LED2_FLASH();
        Sleep(500);
        }
}


使用特权

评论回复
5
yangjiaxu| | 2021-6-6 22:27 | 只看该作者
很强,UCOSIII 这个不错

使用特权

评论回复
6
两只袜子| | 2021-6-15 16:22 | 只看该作者
很强,UCOSIII 这个不错

使用特权

评论回复
7
643757107| | 2021-6-15 18:10 | 只看该作者
还需要懂汇编吗

使用特权

评论回复
8
chenqianqian| | 2021-6-15 20:35 | 只看该作者
都用ARM9了跑Linux不香吗?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

51

主题

3323

帖子

3

粉丝