ARM Cortex M0 cycle counting - Page 1
Forum section: electronics / general

author: amwales
author_rank: Regular Contributor
timestamp: March 14, 2025, 11:25:32 am
content: Hi, I would like to write a piece of code in ARM assembler and would like to count the cycles it take to execute.When I was playing with PICs this was really straight forward as the built in simulator allowed you to inspect the cycle count, start stop the stop watch.Is there something similar available to ARM?I have written a small piece of code in assembler, I haven't assembled or run it yet but would appreciate some eyes.Code:; Assume 40021000 is base address of GPIO port; and 0x14 is offset of ODRldr r1,=40021000 ; load base address of GPIO portldr r2,,#4 ; pop logic to be written to GPIO port; Cycle count.STARTstr r2,[r1, #0x14] ; output value to GPIO port 1ldr r2,,#4 ; pop logic 1ldr r0,,#4 ; pop delay count 1b INNER1 ; branch into middle of delay 2.LOOP1mov r0,r0 ; NOP 1 1mov r0,r0 ; NOP 1 1mov r0,r0 ; NOP 1 1mov r0,r0 ; NOP 1 1.INNER1sub r0, r0, #1 ; decrement delay count 1 1mov r0,r0 ; NOP 1 1cbnz r0, LOOP1 ; loop if count > 0 * * *1 no branch or 2 if branch.END; START->END always completes in; multiples of 8 cycles

author: ataradov
author_rank: Super Contributor
timestamp: March 14, 2025, 01:44:03 pm
content: The easiest way to count cycles is to use SysTick timer. It runs on the core clock. Read the count value at the beginning and at the end of the timed code. A simple math will tell you a number of cycles it took.For Cortex-Mx devices emulating the core alone is not enough for timing, since it depends on the memories (flash may have wait states and caches) and other masters on the bus (DMA, for example). And typical CM systems are way more complicated than PICs to emulate accurately.At the same time, assuming zero wait state memory and no other masters on the bus, you can calculate the timing, since instruction times are outlines in the core technical reference manual.

author: SiliconWizard
author_rank: Super Contributor
timestamp: March 14, 2025, 01:55:27 pm
content: The way that makes most sense on Cortex-M is to use CYCCNT, which is meant for exactly that. Bummer though, it's usually not availble on the M0, so yes, using a timer is probably your best bet.If on a Cortex-M3/4 or higher, do use CYCCNT.

author: brucehoult
author_rank: Super Contributor
timestamp: March 14, 2025, 02:01:13 pm
content: https://x.com/i/grok/share/83FWHOWHvEUNLWCyhhs9Ng3TZ

author: amwales
author_rank: Regular Contributor
timestamp: March 14, 2025, 02:52:01 pm
content: Thanks bruce that looks very interesting.Ok so I made some modifications after seeing my mistake pointed out by grokCode:; Assume 40021000 is base address of GPIO port; and 0x14 is offset of ODRldr r1,=40021000 ; load base address of GPIO portldr r2,,#4 ; pop logic to be written to GPIO port; Cycle count.STARTstr r2,[r1, #0x14] ; output value to GPIO port 2ldr r2,,#4 ; pop logic 2ldr r0,,#4 ; pop delay count 2b INNER1 ; branch into middle of delay 2.LOOP1mov r0,r0 ; NOP 1mov r0,r0 ; NOP 1mov r0,r0 ; NOP 1mov r0,r0 ; NOP 1mov r0,r0 ; NOP 1mov r0,r0 ; NOP 1mov r0,r0 ; NOP 1.INNER1sub r0, r0, #1 ; decrement delay count 1 1cbnz r0, LOOP1 ; loop if count > 0 * * *1 no branch or 2 if branch.END; START->END always completes in; multiples of 10 cyclesGrok seems to agree with my fixes and the final analysis that the it take 10N cycles where N is the delay count.I will need to verify the results on hardware.

author: brucehoult
author_rank: Super Contributor
timestamp: March 14, 2025, 03:10:53 pm
content: It's crazy what a fancy version of T9 can do now.

author: jnk0le
author_rank: Regular Contributor
timestamp: March 14, 2025, 06:19:22 pm
content: Taken branches are 2 cycle on M0+, M0 is 3.Also there is no cbnz instruction on armv6-m, and it doesn't go backwards.

author: amwales
author_rank: Regular Contributor
timestamp: March 14, 2025, 10:33:12 pm
content: Thanks for the comment about cbnz being missing.What do you mean when you say it doesn't go backwards?

author: dave j
author_rank: Regular Contributor
timestamp: March 15, 2025, 11:53:19 am
content: Quote from: amwales on March 14, 2025, 10:33:12 pmUnlike normal branch instructions, the compare and branch ones will only branch forwards (seehere).In your case you can useCode:subs r0, r0, #1bne LOOP1instead with the same performance.