Hello,FreeRTOS!

官网链接

正点原子教程手册

DEMO1: Blink_LED移植

按照教程移植的时候,编译出来会有报错

..\OBJ\LED.axf: Error: L6200E: Symbol PendSV_Handler multiply defined (by port.o and stm32f10x_it.o).

..\OBJ\LED.axf: Error: L6200E: Symbol SVC_Handler multiply defined (by port.o and stm32f10x_it.o).

报错信息显示 PendSV_HandlerSVC_Handlerportstm32f10x_it里面重复定义了。网上查到了有人说要把配置文件FreeRTOSConfig.h里的宏定义注释掉

1
2
#define xPortPendSVHandler 	PendSV_Handler
#define vPortSVCHandler SVC_Handler

但是这两个是与与中断函数有关的配置,直接注释掉肯定不合适。在stm32法f10x_it.c里面找到这两个函数是这样的

1
2
3
4
5
6
7
void SVC_Handler(void)
{
}

void PendSV_Handler(void)
{
}

所以选择将这两个函数给注释掉(实际上教程看到后面发现这几个函数早晚要注释掉的),这样这两个函数分别会指向port.c里面的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
__asm void vPortSVCHandler( void )
{
/* *INDENT-OFF* */
PRESERVE8

ldr r3, = pxCurrentTCB /* Restore the context. */
ldr r1, [ r3 ] /* Use pxCurrentTCBConst to get the pxCurrentTCB address. */
ldr r0, [ r1 ] /* The first item in pxCurrentTCB is the task top of stack. */
ldmia r0 !, { r4 - r11 } /* Pop the registers that are not automatically saved on exception entry and the critical nesting count. */
msr psp, r0 /* Restore the task stack pointer. */
isb
mov r0, # 0
msr basepri, r0
orr r14, # 0xd
bx r14
/* *INDENT-ON* */
}

__asm void xPortPendSVHandler( void )
{
extern uxCriticalNesting;
extern pxCurrentTCB;
extern vTaskSwitchContext;

/* *INDENT-OFF* */
PRESERVE8

mrs r0, psp
isb

ldr r3, =pxCurrentTCB /* Get the location of the current TCB. */
ldr r2, [ r3 ]

stmdb r0 !, { r4 - r11 } /* Save the remaining registers. */
str r0, [ r2 ] /* Save the new top of stack into the first member of the TCB. */

stmdb sp !, { r3, r14 }
mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY
msr basepri, r0
dsb
isb
bl vTaskSwitchContext
mov r0, #0
msr basepri, r0
ldmia sp !, { r3, r14 }

ldr r1, [ r3 ]
ldr r0, [ r1 ] /* The first item in pxCurrentTCB is the task top of stack. */
ldmia r0 !, { r4 - r11 } /* Pop the registers and the critical nesting count. */
msr psp, r0
isb
bx r14
nop
/* *INDENT-ON* */
}

FreeRTOSConfig.h

​ 这一部分在教程中有详细的讲解,在这里摘录过来,全部记住可能不太容易,主要是在具体使用的时候能方便具体查看就行了。

INCLUDE_

INCLUDE_xTaskGetSchedulerState

INCLUDE_vTaskPrioritySet

INCLUDE_uxTaskPriorityGet

INCLUDE_vTaskDelete

INCLUDE_vTaskCleanUpResources

INCLUDE_vTaskSuspend

INCLUDE_vTaskDelayUntil

INCLUDE_vTaskDelay

INCLUDE_eTaskGetState

INCLUDE_xTimerPendFunctionCall

config

DEMO2:中断屏蔽

中断屏蔽寄存器

  • PRIMASK

PRIMASK 用于禁止除 NMI 和 HardFalut 外的所有异常和中断,清除后使能中断

  • FAULTMASK

与 PRIMASK相比 , FAULTMASK 可以连 HardFault 都屏蔽掉 ,它在退出时自动清零。

  • BASEPRI

在有些场合需要对中断屏蔽进行更细腻的控制, 比如只屏蔽优先级低于某
一个阈值的中断。那么这个作为阈值的优先级值存储在哪里呢?BASEPRI 寄存器中。如果向 BASEPRI 写 0 的话就会停止屏蔽中断。

中断屏蔽的配置宏

​ FreeRTOS 的开关中断是操作 BASEPRI 寄存器来实现的,它可以关闭低于某个阈值的中断,高于这个阈值的中断就不会被关闭 。

configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY

​ 此宏用来设置 FreeRTOS 系统可管理的最大优先级,也就是BASEPRI寄存器说的那个阈值优先级,这个大家可以自由设置,这里我设置为了 5。也就是高于 5 的优先级(优先级数小于 5)不归 FreeRTOS 管理。

configMAX_SYSCALL_INTERRUPT_PRIORITY

​ 此宏是 configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 左移 4 位而来的。此宏设置好以后,低于此优先级的中断可以安全的调用 FreeRTOS 的 API 函数,高于此优先级的中断 FreeRTOS 是不能禁止的,中断服务函数也不能调用 FreeRTOS 的 API 函数!

临界段代码:

​ 临界段代码也叫做临界区,是指那些必须完整运行,不能被打断的代码段,比如有的外设的初始化需要严格的时序,初始化过程中不能被打断。FreeRTOS 在进入临界段代码的时候需要关闭中断,当处理完临界段代码以后再打开中断。

任务级临界段代码保护函数

任务中的临界段代码语句使用的保护函数

  • taskENTER_CRITICAL()
  • taskEXIT_CRITICAL()

示例:

1
2
3
4
5
6
7
8
9
10
11
12
void taskcritical_test(void)
{
while(1)
{
taskENTER_CRITICAL();//进入临界区

......

taskEXIT_CRITICAL();//退出临界区
vTaskDelay(1000);
}
}

中断级临界段代码保护函数

中断函数中的临界段代码语句使用的保护函数

  • taskENTER_CRITICAL_FROM_ISR()
  • taskEXIT_CRITICAL_FROM_ISR()

示例:

1
2
3
4
5
6
7
8
9
10
11
12
void TIM3_IRQHandler(void)
{
if(TIM_GetITStatus(TIM3,TIM_IT_Update)==SET) //溢出中断
{
status_value=taskENTER_CRITICAL_FROM_ISR();

......

taskEXIT_CRITICAL_FROM_ISR(status_value);
}
TIM_ClearITPendingBit(TIM3,TIM_IT_Update); //清除中断标志位
}