Arm Community
Arm Community
  • Site
  • User
  • Site
  • Search
  • User
  • Groups
    • Research Collaboration and Enablement
    • DesignStart
    • Education Hub
    • Innovation
    • Open Source Software and Platforms
  • Forums
    • AI and ML forum
    • Architectures and Processors forum
    • Arm Development Platforms forum
    • Arm Development Studio forum
    • Arm Virtual Hardware forum
    • Automotive forum
    • Compilers and Libraries forum
    • Graphics, Gaming, and VR forum
    • High Performance Computing (HPC) forum
    • Infrastructure Solutions forum
    • Internet of Things (IoT) forum
    • Keil forum
    • Morello Forum
    • Operating Systems forum
    • SoC Design and Simulation forum
    • 中文社区论区
  • Blogs
    • AI and ML blog
    • Announcements
    • Architectures and Processors blog
    • Automotive blog
    • Graphics, Gaming, and VR blog
    • High Performance Computing (HPC) blog
    • Infrastructure Solutions blog
    • Innovation blog
    • Internet of Things (IoT) blog
    • Operating Systems blog
    • Research Articles
    • SoC Design and Simulation blog
    • Smart Homes
    • Tools, Software and IDEs blog
    • Works on Arm blog
    • 中文社区博客
  • Support
    • Arm Support Services
    • Documentation
    • Downloads
    • Training
    • Arm Approved program
    • Arm Design Reviews
  • Community Help
  • More
  • Cancel
Arm mbed 中文技术讨论区
  • 中文社区
  • Jump...
Arm mbed 中文技术讨论区
中文mbed博客 Simplify your code with abed-events in mbed OS 5.2 !
  • 中文mbed博客
  • Forum
  • Videos
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • Jump...
  • Cancel
  • New
Arm mbed 中文技术讨论区 requires membership for participation - click to join
More blogs in Arm mbed 中文技术讨论区
  • 中文mbed博客

 

Tags
Actions
  • RSS
  • More
  • Cancel
Related blog posts
Related forum threads

Simplify your code with abed-events in mbed OS 5.2 !

Lisa.Liu
Lisa.Liu
March 3, 2017

In mbed OS 5.2, we introduced mbed-events, an eventing system that can run in an RTOS thread. Using an event loop is very useful to defer execution of code to a different context. An example would be to defer execution from an interrupt context (ISR) to the main loop, or to defer execution from the high-priority thread to a lower priority thread. Now that mbed-events is part of mbed OS 5.2, we'd like to show how this can be used to improve your applications.

For more information about the mbed-events library, have a look at the documentation. All code in this blog post was tested against mbed OS 5.2.3.

Calling printf in an interrupt context

The following program has probably been written by anyone learning how to program microcontrollers. It registers an interrupt handler when a button is pressed, and then calls printf from the ISR.

Naive approach

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include "mbed.h"
 
DigitalOut led(LED1);
InterruptIn btn(SW2);
 
void do_something() {
  led = !led;
  printf("Toggle LED!\r\n"); // CRASH! Blocking call in ISR...
}
 
int main() {
  btn.fall(&do_something);
 
  while (1) { }
}

When you compile this code with ARMCC, the program will crash right after toggling the LED. This is because calls to stdio (like printf) are guarded by mutexes in the ARM C standard library, and mutex functions cannot be called from an ISR. We can get around this by signalling the main thread from the ISR and do the printf call in there. That's especially confusing when teaching beginners, as now we need to explain the concept of Semaphores or Mailboxes as well.

Using a Semaphore

 

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
#include "mbed.h"
 
DigitalOut led(LED1);
InterruptIn btn(SW2);
 
Semaphore updates(0);
 
void do_something() {
  // release the semaphore
  updates.release();
}
 
int main() {
  btn.fall(&do_something);
 
  while (1) {
    // wait for the semaphore to be released from the ISR
    int32_t v = updates.wait();
 
    // now this runs on the main thread, and is safe
    if (v == 1) {
      led = !led;
      printf("Toggle LED!\r\n");
    }
  }
}

While this works, it's a lot more unclear, and we need to build a state machine to determine why the semaphore was released if we're adding more interrupts. Preferably we'd also run this in a separate thread.

With mbed-events we can easily spin up a new RTOS thread with the event loop running in it, and we can defer from ISR to that thread in one line of code.

Using mbed-events

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include "mbed.h"
 
DigitalOut led(LED1);
InterruptIn btn(SW2);
 
// create an event queue
EventQueue queue;
 
void do_something() {
  // this now runs in the context of eventThread, instead of in the ISR
  led = !led;
  printf("Toggle LED!\r\n");
}
 
int main() {
  // create a thread that'll run the event queue's dispatch function
  Thread eventThread;
  eventThread.start(callback(&queue, &EventQueue::dispatch_forever));
 
  // wrap calls in queue.event to automatically defer to the queue's thread
  btn.fall(queue.event(&do_something));
 
  while (1) {}
}

When the interrupt fires, it now automatically defers calling the do_something function to the other thread, from where it's safe to call printf. In addition, we don't need to taint our main thread's main loop with program logic.

Manually deferring from ISR to a thread

The downside of this approach is that both the toggling of the LED and the printf call are now executed outside the ISR and thus are not guaranteed to run straight away. We can work around this by toggling the LED from the ISR, then manually deferring the printf event to the thread.

 

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
#include "mbed.h"
 
DigitalOut led(LED1);
InterruptIn btn(SW2);
 
EventQueue queue;
 
void do_something_outside_irq() {
  // this does not run in the ISR
  printf("Toggle LED!\r\n");
}
 
void do_something_in_irq() {
  // this runs in the ISR
  led = !led;
 
  // then defer the printf call to the other thread
  queue.call(&do_something_outside_irq);
}
 
int main() {
  Thread eventThread;
  eventThread.start(callback(&queue, &EventQueue::dispatch_forever));
 
  btn.fall(&do_something_in_irq);
 
  while (1) {}
}

Mixing high priority and low priority events

We can differentiate between the importance of events by using multiple threads that run with different priorities. We can easily add a Ticker to the program which toggles LED2 every second, which runs with a higher priority than the printf calls by creating a second event queue.

 

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
#include "mbed.h"
 
DigitalOut led1(LED1);
DigitalOut led2(LED2);
InterruptIn btn(SW2);
 
EventQueue printfQueue;
EventQueue eventQueue;
 
void blink_led2() {
  // this runs in the normal priority thread
  led2 = !led2;
}
 
void print_toggle_led() {
  // this runs in the lower priority thread
  printf("Toggle LED!\r\n");
}
 
void btn_fall_irq() {
  led1 = !led1;
 
  // defer the printf call to the low priority thread
  printfQueue.call(&print_toggle_led);
}
 
int main() {
  // low priority thread for calling printf()
  Thread printfThread(osPriorityLow);
  printfThread.start(callback(&printfQueue, &EventQueue::dispatch_forever));
 
  // normal priority thread for other events
  Thread eventThread(osPriorityNormal);
  eventThread.start(callback(&eventQueue, &EventQueue::dispatch_forever));
 
  // call blink_led2 every second, automatically defering to the eventThread
  Ticker ledTicker;
  ledTicker.attach(eventQueue.event(&blink_led2), 1.0f);
 
  // button fall still runs in the ISR
  btn.fall(&btn_fall_irq);
 
  while (1) {}
}

Conclusion

mbed-events makes it a lot easier to defer calls from one context to another, whether it's from an ISR back to a user thread, or from one thread to another. It also makes it easy to prioritise certain events over other events, and does not require you to write your own state machine or taint your main loop. Since it's a one-liner (wrap the callback in queue.event()) to wrap a call that would normally run in an ISR, it's also very friendly for beginners.

Anonymous
中文mbed博客
  • test 東芝、パソコン事業子会社をシャープに売却

    Song Bin 宋斌
    Song Bin 宋斌
    test [東京 5日 ロイター] - シャープ<6753.T>は5日、東芝<6502.T>のパソコン事業を買収することで合意したと発表した。買収額は約40億円。東芝のパソコン関連製品と同社のディスプレーやセンサーなどを融合することで、人工知能(AI)やすべてのモノがインターネットにつながるIoT(インターネット・オブ・シングス)事業を強化する。 パソコン事業を手掛ける東芝クライアントソリューション…
    • June 5, 2018
  • [招聘要求] 我們合作夥伴华域汽车招聘IoT开发工程师(嵌入式方向)

    Caroline
    Caroline
    工作职责: 1. 基于Arduino/Raspberry Pi等开源硬件进行IoT相关开发 2. 与开发相关的文档撰写 能力要求: 1. 熟悉并掌握C/C++开发语言,有三年以上开发经验 2. 熟悉Arduino/Raspberry Pi等开源硬件开发平台 3. 具有良好的沟通能力及分析解决问题能力,有责任心,能吃苦耐劳,具有较强的任务执行能力。 4. 有ARM Mbed相關經驗优先考慮5. 有Python开发能力优先…
    • October 20, 2017
  • Mbed Connect 11/6登陆上海!

    Caroline
    Caroline
    Mbed Connect 开发者实践工作坊登陆上海 11月6日 上海浦东嘉里大酒店     Arm将于11月6日上海的年度技术论坛上,同期举办Mbed Connect开发者实践工作坊。参加工作坊,你可以深入了解在Mbed IoT设备平台上如何开发可扩展的物联网解决方案,马上注册。这是一次难得的机会,可以与Mbed专家进行面对面的学习,与来自于Mbed生态系统有经验的开发者展开交流。与会观众可以先通过Arm年度技术论坛上的主旨演讲洞悉市场趋势和热点…
    • October 18, 2017