Cortex-m3进阶

1,FreeRTOS详解

1:FreeRTOS任务调度器开启

vTaskStartScheduler

1、创建空闲任务

2、如果使能了软件定时器,创建软件定时器

3、关中断

4、初始化一些静态全局变量

5、xPortStartScheduler

xPortStartScheduler

1、设置PendSV和Systick中断优先级

2、初始化嘀嗒定时器,中断周期,中断使能,systick使能

3、如果MCU有FPU的话,开启FPU

4、如果使用FPU的话,开启惰性压栈

5、prvStartFirstTask,开启第一个任务

6、SVC 0;引起SVC中断

2:FreeRTOS任务创建

xTaskCreate()

1、申请堆栈内存

2、申请任务控制块内存

3、调用prvInitialiseNewTask()初始化任务

prvInitialiseNewTask()

1、初始化堆栈为0xa5,可选功能

2、获取栈顶,保存在pxTopOfStack。

3、保存任务名字,到pxNewTCB->pcTaskName

4、保存任务优先级到pxNewTCB->uxPriority

5、初始化两个列表项xStateListItem和xEventListItem

6、初始化各种任务控制块成员变量

7、调用pxPortInitialiseStack(),初始化堆栈

8、保存/记录任务句柄,其实就是任务控制块。

prvAddNewTaskToReadyList()

1、uxCurrentNumberOfTasks加一,记录系统中有多少个任务

2、如果创建的是第一个任务,初始化相关列表,使用函数uxCurrentNumberOfTasks()

3、调用prvAddTaskToReadyList,将任务添加到就序列表中

4、如果新创建的任务优先级比当前任务优先级高,那么调用taskYIELD_IF_USING_PREEMPTION()进行任务切换

prvAddTaskToReadyList()

1、将uxTopReadyPriority相应的bit置1,表示相应优先级有就序任务

2、将新创建的任务添加到对应的就序列表中去,末尾插入。比如优先级5,pxReadyTasksLists[5]

3:任务删除、挂起和恢复过程

任务删除

vTaskDelete(TaskHandle_t xTaskToDelete)

1、根据任务句柄获取任务控制块,如果任务句柄为NULL,表示删除任务自身

2、将要删除的任务从就序列表中移除,并且如果相应的优先级下只有这一个任务那么复位相应的优先级位

3、如果任务等待某些事件的话那就将此任务从相应的时间列表中移除

4、如果删除的是任务自身,那么将任务添加到列表xTasksWaitingTermination中。任务堆栈,控制块的内存释放在空闲任务中完成

5、uxCurrentNumberOfTasks减一,表示当前系统任务减一。如果删的不是任务自身

6、释放任务控制块和任务堆栈内存

7、如果删除的是任务自身,最后需要主动发起任务切换

任务挂起

void vTaskSuspend(TaskHandle_t xTaskToSuspend)

1、根据任务句柄获取任务控制块,如果任务句柄为NULL,表示删除任务自身

2、将要挂起的任务从相应的状态列表和事件中移除

3、将要挂起的任务添加到挂起任务列表xSuspendedTaskList里面去

4、如果挂起的是任务自身,而且任务调度器正在运行,那么需要进行一次任务切换

任务恢复

void vTaskResume(TaskHandle_t xTaskToResume)

1、判断要恢复的任务是否为挂起任务?

2、将要恢复的任务从挂起任务列表xSuspendTaskList移除

3、调用函数prvAddTaskToReadyList()将任务添加到就序列表中。

4、如果刚刚恢复的任务优先级比当前正在运行的任务优先级高,那么进行一次任务切换。

4:FreeRTOS任务切换

PendSV异常

1、任务切换具体过程是在PendSV中断服务函数里面

2、如何一起PendSV中断,ICSR寄存器bit28置1。

3、关于PendSV具体的内容,建议大家参考权威指南相关章节

任务切换场合

1、执行系统调用如:taskYILED(),vTaskDelay()->portYIELD_WIRHIN_API()->portYIELD()

2、systick中断服务函数

PendSV_Handler()或xPortPendSVHandler()

1、判断是否使用FPU。如果使用的话将S16-S31入栈。EXC_RETURN当处理异常的时候bit4会被CONTROL的FPCA位替代。判断EXC_RETURN的bit4是否为1,如果为1需要保存浮点寄存器。

2、R4-R11 R14入栈

3、关闭中断

4、调用vTaskSwitchContext,获取下一个要运行任务

5、打开中断

6、获取要切换的任务的栈顶指针

7、R4-R11,R14出栈

8、判断是否使用FPU,如果使用的话S16-S31出栈

9、任务切换完成

2,按键事件

stm8用定时器中断代替轮询读取GPIO监听cortex-m3主板是否休眠

3,stm32 各种类型错误:HardFault_Handler、MemManage_Handler、BusFault_Handler、UsageFault_Handler

STM32出现HardFault_Handler故障的原因主要有两个方面:

1、内存溢出或者访问越界。这个需要自己写程序的时候规范代码,遇到了需要慢慢排查。

2、堆栈溢出。增加堆栈的大小。

MemManage_Handler:访问了内存管理单元(MPU)定义的不合法的内存区域,比如向只读区域写入数据

BusFault_Handler:在fetch指令、数据读写、fetch中断向量或中断时存储恢复寄存器栈情况下,检测到内存访问错误则产生        BusFault。

UsageFault_Handler:检测到未定义指令或在存取内存时有未对齐。还可以通过软件配置是否检测到除数为0和其它未对齐内存访问也产生该异常,默认关闭,需要在工程初始化时配置:

             SCB->CCR |= 0x18;      // 开启除数为0和内存未对齐错误中断

HardFault_Handler:在调试程序过程中,这种异常最常见。上面三种异常发生任何一种异常都会引起HardFault,在上面的三种异常未使能的情况下,默认发生异常时进入HardFault中断服务程序。使能前三种异常也要在初始化时配置:

             SCB->SHCSR |= 0x00007000;   // enable Usage Fault, Bus Fault, and MMU Fault 

在默认复位初始化时,HardFault使能,其它三者不使能,因此当程序中出现不合法内存访问(一般是指针错误引起)或非法的程序行为(一般就是数学里面常见的除0)时都将产生HardFault中断。

4,Cortex-M CPU架构基础

不同于老的经典arm处理器(例如:ARM7,ARM9),ARM Cortex-M 处理器有一个非常不同的架构,Cortex-M是一个家族系列,其中包括Cortex M0/M3/M4/M7多个不同型号,每个型号之间会有些区别,例如Cortex-M4比Cortex-M3多了浮点计算功能等,但它们的编程模型基本是一致的。

寄存器简介

Cortex-M系列CPU的寄存器组里有R0~R15共16个通用寄存器组和若干特殊功能寄存器,如图所示:

通用寄存器组里的R13作为堆栈指针寄存器(Stack Pointer,SP);R14作为连接寄存器(Link Register,LR),用于在调用子程序时,存储返回地址;R15作为程序计数器(Program Counter,PC),其中堆栈指针寄存器可以是主堆栈指针(MSP),也可以是进程堆栈指针(PSP)。

特殊功能寄存器包括程序状态字寄存器组(PSRs)、终端屏蔽寄存器组(PRIMASK、FAULTMASK、BASEPRI)、控制寄存器(CONTROL),可以通过MSR\MRS指令来访问特殊功能寄存器,例如:

MRS   R0,  CONTROL  ;读取CONTROL到R0中

MSR   CONTROL,   R0 ;写入R0到CONTROL寄存器中

程序状态字寄存器里保存算术与逻辑标志,例如负数标志,零结果标志,溢出标志等等。中断屏蔽寄存器组控制Cortex-M的中断除能。控制寄存器用来定义特权级别和当前使用哪个堆栈指针。

如果是具有浮点单元的COrtex-M4或者Cortex-M7,控制寄存器也用来指示浮点单元当前是否在使用,浮点单元包含了32个浮点通用寄存器S0-S31和特殊FPSCR寄存器(Floating point status and control register)。

操作模式和特权级别

Cortex-M引入了操作模式和特权级别的概念,分别为线程模式和处理模式,如果进入异常或中断处理则进入处理模式,其他情况则为线程模式。

Cortex-M有两个运行级别,分别为特权级和用户级,线程模式可以工作在特权级或者用户级,而处理模式总工作在特权级,可通过CONTROL特殊寄存器控制,工作模式状态切换情况如上图所示。

Cortex-M的堆栈寄存器SP对应两个物理寄存器MSP和PSP,MSP为主堆栈,PSP为进程堆栈,处理模式总是使用MSP作为堆栈,线程模式可以选择使用MSP或PSP作为堆栈,同样通过CONTROL特殊寄存器控制。复位后,Cortex-M默认进入线程模式、特权级、使用MSP堆栈。

嵌套向量中断控制器

Cortex-M中断控制器名为NVIC(嵌套向量中断控制器),支持中断嵌套功能。当一个中断触发并且系统响应时,处理器硬件会将当前运行位置的上下文寄存器自动压入中断栈中,这部分的寄存器包括PSR、PC、LR、R12、R3-R0寄存器。

当系统正在服务一个中断时,如果有一个更高优先级的中断触发,那么处理器同样会打断当前运行的中端服务程序,然后把这个中断服务程序上下文的PSR、PC、LR、R12、R3-R0寄存器自动保存到中断栈中。

PendSV系统调用

PendSV也称为可悬起的系统调用,它是一种异常,可以像普通的中断一样被挂起,它是专门用来辅助操作系统进行上下文切换的。PendSV异常会被初始化为最低优先级的异常。每次需要进行上下文切换的时候,会手动触发PendSV异常,在PendSV异常处理函数中进行上下文切换。

中断向量表

中断向量表是所有中断处理程序的入口,把一个函数(用户中断服务程序)同一个虚拟中断向量表中的中断向量联系在一起。当中断向量对应中断发生的时候,被挂起的用户中断服务函数程序就会被调用执行。

在Cortex-M内核上,所有中断都采用中断向量表的方式进行处理,即当一个中断触发时,处理器将直接判定是哪个中断源,然后直接跳转到相应的固定位置进行处理,每个中断服务程序必须排列在一起放在统一的地址上(这个地址必须要设置到NVIC的中断向量偏移寄存器中)。中断向量表一般由一个数组定义或在起始代码中给出,默认采用起始代码给出:

 
  1. __Vectors DCD __initial_sp ; Top of Stack

  2. DCD Reset_Handler ; Reset 处理函数

  3. DCD NMI_Handler ; NMI 处理函数

  4. DCD HardFault_Handler ; Hard Fault 处理函数

  5. DCD MemManage_Handler ; MPU Fault 处理函数

  6. DCD BusFault_Handler ; Bus Fault 处理函数

  7. DCD UsageFault_Handler ; Usage Fault 处理函数

  8. DCD 0 ; 保留

  9. DCD 0 ; 保留

  10. DCD 0 ; 保留

  11. DCD 0 ; 保留

  12. DCD SVC_Handler ; SVCall 处理函数

  13. DCD DebugMon_handler ; Debug Monitor 处理函数

  14. DCD 0 ; 保留

  15. DCD PendSV_handler ; PendSV 处理函数

  16. DCD SysTick_handler ; SysTick 处理函数

  17. ... ...

  18. NMI_Handler PROC

  19. EXPORT NMI_Handler [WEAK]

  20. B .

  21. ENDP

  22. HardFault_Handler PROC

  23. EXPORT HardFault_Handler [WEAK]

  24. B .

  25. ENDP

  26. ... ...

以SysTick中断为例,在系统启动代码中,需要填上SysTick_Handler中断入口函数,然后实现该函数即可对SysTick中断进行响应。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值