# Profiling Firmware on Cortex-M | Interrupt

**URL:** https://community.memfault.com/t/profiling-firmware-on-cortex-m-interrupt/210
**Category:** Blog
**Created:** [June 3, 2020, 5:22am UTC](https://community.memfault.com/t/profiling-firmware-on-cortex-m-interrupt/210 "2020-06-03T05:22:06Z")
**Posts on this page:** 16
**Page:** 1

<div class="post-metadata">

### Author: ![discobot](https://yyz2.discourse-cdn.com/flex030/user_avatar/community.memfault.com/discobot/32/1_2.png) [@discobot](https://community.memfault.com/u/discobot)
#### Post date: [June 3, 2020, 5:22am UTC](https://community.memfault.com/t/profiling-firmware-on-cortex-m-interrupt/210/1 "2020-06-03T05:22:07Z")

</div>

Although microcontrollers in 2020 sometimes come with GHz clock frequencies and even multiple cores, performance is a major concern when developing embedded applications. Indeed, most firmware projects face some real-time constraints which must be carefully managed.

* * *
This is a companion discussion topic for the original entry at [https://interrupt.memfault.com/blog/profiling-firmware-on-cortex-m](https://interrupt.memfault.com/blog/profiling-firmware-on-cortex-m)

---

<div class="post-metadata">

### Author: ![Silviu](https://avatars.discourse-cdn.com/v4/letter/s/b5a626/32.png) [@Silviu](https://community.memfault.com/u/Silviu)
#### Post date: [June 3, 2020, 10:44pm UTC](https://community.memfault.com/t/profiling-firmware-on-cortex-m-interrupt/210/2 "2020-06-03T22:44:17Z")

</div>

Wish this was out a while back, half of the stuff described here I had to read through the programmers reference manual and arm docs to learn it. I bet it will save some time for others down the road. Nice artictle!

---

<div class="post-metadata">

### Author: ![francois](https://avatars.discourse-cdn.com/v4/letter/f/77aa72/32.png) [@francois](https://community.memfault.com/u/francois)
#### Post date: [June 3, 2020, 10:55pm UTC](https://community.memfault.com/t/profiling-firmware-on-cortex-m-interrupt/210/3 "2020-06-03T22:55:01Z")

</div>

Thanks for the kind words @Silviu! I also wish this had existed before ;-).

---

<div class="post-metadata">

### Author: ![Rajah](https://avatars.discourse-cdn.com/v4/letter/r/e9a140/32.png) [@Rajah](https://community.memfault.com/u/Rajah)
#### Post date: [June 5, 2020, 5:08pm UTC](https://community.memfault.com/t/profiling-firmware-on-cortex-m-interrupt/210/4 "2020-06-05T17:08:23Z")

</div>

An article I had been waiting for!!! I am the poor man in the poorman’s profiling. I have been using the sampling method for all my profiling so far. I happen to have the exact STM32 dev kit, I cannot wait to try the example project. Thanks very much for pulling all the information to one single post.

Rajah

---

<div class="post-metadata">

### Author: ![Rajah](https://avatars.discourse-cdn.com/v4/letter/r/e9a140/32.png) [@Rajah](https://community.memfault.com/u/Rajah)
#### Post date: [June 5, 2020, 5:59pm UTC](https://community.memfault.com/t/profiling-firmware-on-cortex-m-interrupt/210/5 "2020-06-05T17:59:03Z")

</div>

I followed the steps in the example and found the code is flashed but no LCD update. I tried the STM32 demo for the dev board and everything worked fine. So I can confirm that my board is working. I cleaned the libopemcm3 repo and rebuilt (you have to first make a full build before you can build just from the example that you want. The first build creates the library). I followed the steps to flash the code and still nothing on the screen. Upon checking gdb, it looks like micro is in la la land due to possible vector table issue. Anyone else seeing similar issue?

```
Program received signal SIGINT, Interrupt.
reset_handler () at ../../cm3/vector.c:67
67 for (src = &_data_loadaddr, dest = &_data;

```

Thanks,  
Rajah

---

<div class="post-metadata">

### Author: ![francois](https://avatars.discourse-cdn.com/v4/letter/f/77aa72/32.png) [@francois](https://community.memfault.com/u/francois)
#### Post date: [June 5, 2020, 6:15pm UTC](https://community.memfault.com/t/profiling-firmware-on-cortex-m-interrupt/210/6 "2020-06-05T18:15:00Z")

</div>

Hey Rajah,

Sorry you’re having issues reproducting the results. I double check and did not have to modify anything in libopencm3 or the example to get it to work on my STM32F429I-DISC1 board (is that the same model you have?).

One thing worth checking: I’m on a slightly older commit of the library. libopencm3-examples commit 9830486509cb93b4504aa3a0207e9a43f3308d28, and libopencm3 submodule commit 7be50a5e75ed2d163d38a6759347c5e778ac02ab. Perhaps a regression was introduced recently?

---

<div class="post-metadata">

### Author: ![Rajah](https://avatars.discourse-cdn.com/v4/letter/r/e9a140/32.png) [@Rajah](https://community.memfault.com/u/Rajah)
#### Post date: [June 6, 2020, 5:48am UTC](https://community.memfault.com/t/profiling-firmware-on-cortex-m-interrupt/210/7 "2020-06-06T05:48:20Z")

</div>

Hi Francois, thank you for the quick response. I just noticed that my eval kit is STM32F429I-DISC **O** and not STM32F429I-DISC **1**. The main difference b/w them is the default state of Rx and Tx jumpers for VCOM over USB. STM32F429I-DISC **O** has open SB11 and SB15, while STM32F429I-DISC **1** has them closed by default. I will make this change and try your suggestion about the commit id on git.

Thanks,  
Rajah

---

<div class="post-metadata">

### Author: ![ayoub](https://avatars.discourse-cdn.com/v4/letter/a/c89c15/32.png) [@ayoub](https://community.memfault.com/u/ayoub)
#### Post date: [June 7, 2020, 10:27am UTC](https://community.memfault.com/t/profiling-firmware-on-cortex-m-interrupt/210/8 "2020-06-07T10:27:35Z")

</div>

Hi there, thank you for this article!

As you pointed out the last method doesn’t really work for multi-threaded applications on MCU. Most of my projects are running FreeRTOS and I was wondering if there is a way in OpenOCD to profile individual threads (or function) without taking into account task switch and IRQs. Do you know if it is possible?

AFAIK OpenOCD supports thread-aware debugging so normally it should be able to “detect” kernel events.

PS: Thank you again, this blog is like heaven for embedded software engineers 🙂

---

<div class="post-metadata">

### Author: ![kisielk](https://yyz2.discourse-cdn.com/flex030/user_avatar/community.memfault.com/kisielk/32/60_2.png) [@kisielk](https://community.memfault.com/u/kisielk)
#### Post date: [June 7, 2020, 10:36pm UTC](https://community.memfault.com/t/profiling-firmware-on-cortex-m-interrupt/210/9 "2020-06-07T22:36:08Z")

</div>

Check out the section in the FreeRTOS docs about tracing:

> **[FreeRTOS trace macros](https://www.freertos.org/rtos-trace-macros.html)**
>
> Trace macros provide a generic mechanism for tracing and analysing the behaviour of a FreeRTOS application

You could define `traceTASK_SWITCHED_IN()` and `traceTASK_SWITCHED_OUT()` to start and stop your profiling counters as necessary when your tasks changed, or even keep separate counters for different tasks based on their task tags.

---

<div class="post-metadata">

### Author: ![daniel](https://avatars.discourse-cdn.com/v4/letter/d/3ec8ea/32.png) [@daniel](https://community.memfault.com/u/daniel)
#### Post date: [June 8, 2020, 6:26am UTC](https://community.memfault.com/t/profiling-firmware-on-cortex-m-interrupt/210/10 "2020-06-08T06:26:39Z")

</div>

Thanks for this excellent post. Quite fascinating what can be achieved with free software!

In the last part you are describing how to measure the runtime of functions.  
This is something we tried to make more accessible using a web-frontend: [https://barebench.com](https://barebench.com)  
It is a free service that lets you define functions and their benchmark input data.  
Using the techniques you described in your blog (DWT/CycleCounter), the precise runtime is measured on the MCU and shown.

---

<div class="post-metadata">

### Author: ![francois](https://avatars.discourse-cdn.com/v4/letter/f/77aa72/32.png) [@francois](https://community.memfault.com/u/francois)
#### Post date: [June 8, 2020, 5:35pm UTC](https://community.memfault.com/t/profiling-firmware-on-cortex-m-interrupt/210/11 "2020-06-08T17:35:26Z")

</div>

> [@ayoub](#):
>
> As you pointed out the last method doesn’t really work for multi-threaded applications on MCU. Most of my projects are running FreeRTOS and I was wondering if there is a way in OpenOCD to profile individual threads (or function) without taking into account task switch and IRQs. Do you know if it is possible?

I think the easiest way to profile your RTOS is to dynamically enable / disable ITM tracing when you switch threads. Many RTOS provide hooks for this (e.g. @kisielk points out `traceTASK_SWITCHED_IN()` in FreeRTOS), but if not it’s relatively easy to implement yourself by modifying your scheduler code.

You _could_ use GDB scripting to setup a breakpoint in the Systick IRQ and automatically enable / disable ITM as needed. This would work but would introduce overhead, as the Poor Man’s Profiler does.

---

<div class="post-metadata">

### Author: ![francois](https://avatars.discourse-cdn.com/v4/letter/f/77aa72/32.png) [@francois](https://community.memfault.com/u/francois)
#### Post date: [June 8, 2020, 5:36pm UTC](https://community.memfault.com/t/profiling-firmware-on-cortex-m-interrupt/210/12 "2020-06-08T17:36:07Z")

</div>

> [@daniel](#):
>
> In the last part you are describing how to measure the runtime of functions.  
> This is something we tried to make more accessible using a web-frontend: [https://barebench.com](https://barebench.com)  
> It is a free service that lets you define functions and their benchmark input data.  
> Using the techniques you described in your blog (DWT/CycleCounter), the precise runtime is measured on the MCU and shown.

Interesting. Shoot me an email francois - at - memfault if you ever want to chat about BareBench!

---

<div class="post-metadata">

### Author: ![leemagnusson](https://avatars.discourse-cdn.com/v4/letter/l/e480ec/32.png) [@leemagnusson](https://community.memfault.com/u/leemagnusson)
#### Post date: [September 15, 2021, 7:51pm UTC](https://community.memfault.com/t/profiling-firmware-on-cortex-m-interrupt/210/13 "2021-09-15T19:51:06Z")

</div>

I’m trying to get your ITM example to run but having difficulty. In particular it breaks at this point, since that would write 0x1207 to many memory address from what I can see. Is there a part to this that is missing? Just writing 0x1207 by itself with the other commands doesn’t provide any output for me.

> [@discobot](#):
>
> `(gdb) monitor mww 0xE0001000 0x1207 0x103FF`

---

<div class="post-metadata">

### Author: ![flfer](https://avatars.discourse-cdn.com/v4/letter/f/df705f/32.png) [@flfer](https://community.memfault.com/u/flfer)
#### Post date: [January 16, 2024, 3:04pm UTC](https://community.memfault.com/t/profiling-firmware-on-cortex-m-interrupt/210/14 "2024-01-16T15:04:26Z")

</div>

Hello François,

Thank you for this article, it is very interresting !  
I think that a mistake is into the section _ **Enabling PC Sampling Events** _ :

```auto
(gdb) monitor mww 0xE0001000 0x1207 0x103FF

```

Should be replace by :

```auto
(gdb) monitor mww 0xE0001000 0x1207

```

After, you can verify the value of memory with this command :

```auto
(gdb) monitor mdw 0xE0001000

```

---

<div class="post-metadata">

### Author: ![Dingisoul](https://yyz2.discourse-cdn.com/flex030/user_avatar/community.memfault.com/dingisoul/32/260_2.png) [@Dingisoul](https://community.memfault.com/u/Dingisoul)
#### Post date: [March 9, 2024, 11:29am UTC](https://community.memfault.com/t/profiling-firmware-on-cortex-m-interrupt/210/15 "2024-03-09T11:29:05Z")

</div>

Hi [flfer](https://community.memfault.com/u/flfer), I get your point. I think the mww should be fixed with mmw , whith means memory modify (update) word.  
`mmw {reg setbits clearbits}`  
The writer want to make sure the bits been cleared.  
@francois

---

<div class="post-metadata">

### Author: ![gutzchi](https://avatars.discourse-cdn.com/v4/letter/g/b3f665/32.png) [@gutzchi](https://community.memfault.com/u/gutzchi)
#### Post date: [August 21, 2025, 12:34pm UTC](https://community.memfault.com/t/profiling-firmware-on-cortex-m-interrupt/210/16 "2025-08-21T12:34:55Z")

</div>

As per the version of openocd that I am using (0.12.0), the `tpiu` command has changed a bit.

The config I use right now in openocd is as follows:

```auto
tpiu create $_CHIPNAME.tpiu -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0xE0040000     
$_CHIPNAME.tpiu configure -protocol uart -traceclk 24000000 -pin-freq 12000000 -output file.txt
$_CHIPNAME.tpiu enable

```
