freertos时序笔记

最近在使用freertos的一个嵌入式平台中同步freertos中的任务与一个外部中断信号,这里记录下测量学习的过程:

freertos的时钟驱动freertos的任务调度,在freertos中高优先级的任务能够在发生任务调度时打断低优先级任务的执行,在任务被挂起后让出CPU的使用,系统切换到低优先级的任务执行上面, 其中idle_task是freertos中优先级最低的任务。

现在假设我们的系统里面新建了两个任务其中高优先级的任务为task_a, 低优先级的任务为task_b, 这两个任务都有下面的特性:

  • task_a : 这里task_a通过一种精准的延时的方式控制着这个系统的周期,即任务每两个freertos的tick后会被系统运行一次。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
void task_a( void * pvParameters )
{
TickType_t xLastWakeTime;
/* task_a init here */

xLastWakeTime = xTaskGetTickCount(); /* Initialise the xLastWakeTime variable with the current time */
for( ;; )
{
//test_pin high
/* Task code goes here. */
//test_pin low
vTaskDelayUntil( &xLastWakeTime, 2 );
}
}
  • task_b : 这里的task_b 会占满系统的剩余时间导致比task_b 优先级更低的任务无法被系统调用运行。
1
2
3
4
5
6
7
8
9
10
11
void task_b( void * pvParameters )
{
/* task_a init here */

for( ;; )
{
//test_pin high
/* Task code goes here. */
//test_pin low
}
}

这时系统的时序如下

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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
@startuml
scale 100 as 150 pixels

binary "freeRTOS tick" as tick
binary "task_a" as a
binary "task_b" as b

@0
tick is low
a is low
b is low

@10
tick is high
a is low
b is low

@11
tick is low
a is low
b is low

@12
tick is low
a is high
b is low

@168
tick is low
a is low
b is low

@169
tick is low
a is low
b is low

@170
tick is low
a is low
b is high

@189
tick is low
a is low
b is low

@190
tick is low
a is low
b is high

@209
tick is low
a is low
b is low

@210
tick is low
a is low
b is high

@229
tick is low
a is low
b is low

@230
tick is low
a is low
b is high

@249
tick is low
a is low
b is low

@250
tick is high
a is low
b is low

@251
tick is low
a is low
b is low

@252
tick is low
a is low
b is high

@271
tick is low
a is low
b is low

@272
tick is low
a is low
b is high

@291
tick is low
a is low
b is low

@292
tick is low
a is low
b is high

@311
tick is low
a is low
b is low

@312
tick is low
a is low
b is high

@331
tick is low
a is low
b is low

@332
tick is low
a is low
b is high

@351
tick is low
a is low
b is low

@352
tick is low
a is low
b is high

@371
tick is low
a is low
b is low

@372
tick is low
a is low
b is high

@391
tick is low
a is low
b is low

@392
tick is low
a is low
b is high

@411
tick is low
a is low
b is low

@412
tick is low
a is low
b is high

@431
tick is low
a is low
b is low

@432
tick is low
a is low
b is high

@451
tick is low
a is low
b is low

@452
tick is low
a is low
b is high

@471
tick is low
a is low
b is low

@472
tick is low
a is low
b is high

@491
tick is low
a is low
b is low

@492
tick is low
a is low
b is high

@500
tick is high
a is low
b is high

@501
tick is low
a is low
b is high

@502
tick is low
a is high
b is high

@670
tick is low
a is low
b is high

@680
tick is low
a is low
b is low

@681
tick is low
a is low
b is high

@699
tick is low
a is low
b is low
@enduml

这里通过这个时序图可以看出高优先级的任务可以在任务调度时获取CPU的执行时间,打断低优先级任务的执行

现在加入中断并修改任务a的代码如下

  • 中断回调函数:
1
2
3
4
5
6
7
8
void sync_isr( void * arg )
{
//test_pin high
/* ISR handle code goes here */
//test_pin low
/* Unblock the task by releasing the semaphore. */
xSemaphoreGiveFromISR( xSemaphore, NULL);
}
  • task_a :
1
2
3
4
5
6
7
8
9
10
11
void task_a( void * pvParameters )
{
/* task_a init here */
for( ;; )
{
xSemaphoreTake( xSemaphore, LONGTIME);
//test_pin high
/* Task code goes here. */
//test_pin low
}
}

这里也可以使用 vTaskNotifyGiveFromISR或者vTaskResume来通过ISR启动任务。

这里系统时序图如下:

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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
@startuml
scale 100 as 150 pixels

binary "freeRTOS tick" as tick
binary "task_a" as a
binary "task_b" as b
binary "sync_isr" as isr

@0
tick is low
a is low
b is low

@10
tick is high

@11
tick is low

@12
a is high

@168
a is low

@170
b is high

@189
b is low

@190
b is high

@200
isr is high

@201
isr is low

@209
b is low

@210
b is high

@229
b is low

@230
b is high

@249
b is low

@250
tick is high

@251
tick is low

@252
a is high

@370
a is low

@371
b is high

@390
b is low

@391
b is high

@410
b is low

@411
b is high

@430
b is low

@431
b is high

@450
b is low

@451
b is high

@470
b is low

@471
b is high

@490
b is low

@491
b is high

@500
tick is high

@501
tick is low

@511
b is low

@512
b is high

@531
b is low

@532
b is high

@551
b is low

@552
b is high

@571
b is low

@572
b is high

@591
b is low

@592
b is high
@enduml

从上面的时序图可以看出在中断发生时并没有立即将CPU的时间切换到高优先级的任务task_a上面而是等到了下一次的任务调度才切换到task_a上面。从而可能会导致中断响应的不及时。

这里freeRTOS提供一个可以在传递信号量之后立即启动任务切换的能力,这里修改中断代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
void sync_isr( void * arg )
{
//test_pin high
/* ISR handle code goes here */
//test_pin low
/* Unblock the task by releasing the semaphore. */
static BaseType_t xHigherPriorityTaskWoken;
/* Is it time for vATask() to run? */
xHigherPriorityTaskWoken = pdTRUE;
xSemaphoreGiveFromISR( xSemaphore, &xHigherPriorityTaskWoken);
/* start task scheduling */
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}

修改后系统的时序会变为如下:

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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
@startuml
scale 100 as 150 pixels

binary "freeRTOS tick" as tick
binary "task_a" as a
binary "task_b" as b
binary "sync_isr" as isr

@0
tick is low
a is low
b is low

@10
tick is high

@11
tick is low

@12
a is high

@168
a is low

@170
b is high

@189
b is low

@190
b is high

@200
isr is high

@201
isr is low

@202
a is high

@370
a is low

@250
tick is high

@251
tick is low

@371
b is high

@390
b is low

@391
b is high

@410
b is low

@411
b is high

@430
b is low

@431
b is high

@450
b is low

@451
b is high

@470
b is low

@471
b is high

@490
b is low

@491
b is high

@500
tick is high

@501
tick is low

@511
b is low

@512
b is high

@531
b is low

@532
b is high

@551
b is low

@552
b is high

@571
b is low

@572
b is high

@591
b is low

@592
b is high
@enduml

这里在中断isr结束立即启动任务调度可以从上面时序图看出系统立即切换到task_a上面,保证了系统的实时性。