NUC970(ARM9) UCOSIII移植

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




然后实现一个用户中断管理接口

/*************************************************************************************************************************
* 函数			:	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;
    } 
}

//初始化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);		//定时器配置
}

//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);
	}
}


完整的工程链接:https://download.csdn.net/download/cp1300/12797399

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cp1300

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值