Hello, I´m trying to implement a small assembly routine in a cortex M0+ in order to introduce a software controlled delay in microseconds. For performing this, i wrote this small while() routine:
So, knowing exactly what assembly instructions are executing, the clk clock frequency, and the number of clk cycles per instruction, I can calculate the CyclesToDelay value for a desired delay to introduce.Assembly:
__no_operation();0002 73F8 NOPCyclesToDelay--;0002 73FA LDR R1, [R0]0002 73FC SUBS R1, R1, #10002 73FE STR R1, [R0]while (CyclesToDelay > 0)0002 7400 LDR R1, [R0]0002 7402 CMP R1, #00002 7404 BNE 0x000273F8
Instruction clk cycles according https://developer.arm.com/documentation/ddi0432/c/programmers-model/instruction-set-summary are:
NOP 1 clk cycles
LDR 2 clk cycles
SUBS 1 clk cycles
STR 2 clk cycles
CMP 1 clk cycles
BNE 3 clk cycles
Total clk cycles in this routine = 12 clk cycles,CORE_CLK = 48mhzThen,1) 1 CORE_CLK cycle = 1 / 48 us2) 12 CORE_CLK cycles = 12/48 us ( The number of microseconds one loop of this routine should delay)Finally:3) CyclesToDelay * (12/48) = delay_we_want_to_introduce(us)
or CyclesToDelay = delay_we_want_to_inject(us) * 48 / 12However, measuring the delays obtained with this method does not seem to be very accurate. I dont know if this is going to be deterministic or if this is totally possible in this Cortex M0+. Feedback would be appreciated. Many thanks.
I was about to say that you might use the DWT CYCCNT register, as I have done for CM3 and CM4. Alas it appears to be missing from CM0/CM0plus.
For what it's worth, here's the code for CM3/4, it might help you in some way.
static void init(void); static uint32_t ticksPerMilli; /******************************** PUBLIC API *******************************/ void delayMillis( size_t ms ) { if( ticksPerMilli == 0 ) { init(); } // Reset the cycle counter and enable it, so it starts counting DWT->CYCCNT = 0; DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; while( DWT->CYCCNT < (ms * ticksPerMilli) ) ; } void delaySeconds( size_t s ) { delayMillis( s * 1000 ); } /***************************************************************************/ static void init(void) { // Bit mask definitions (*_Msk) are from core_cmN.h // To use DWT, you have to set the Trace Enable bit in DEMCR... CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; /* Trace DEMCR might not be writable from CPU (only debugger??). If that is true, the 'delay via cyccnt' can't be used on this MCU. */ if( !(CoreDebug->DEMCR & CoreDebug_DEMCR_TRCENA_Msk) ) assert(0); // CYCCNT might not be implemented. Assertion as above if( DWT->CTRL & DWT_CTRL_NOCYCCNT_Msk ) assert(0); // SystemCoreClock is a CMSIS Core-managed variable ticksPerMilli = SystemCoreClock / 1000; }
Yes, it seems that this option its not avaliable on this MCU. Thanks anyway,, hehe