Hi, I am getting familiar with my SAMD21G18A (M0 Pro). I've started a new project in AS7. I can't seem to find any delay functions. From what I gathered, there is a delay.h, but I can't seem to find it.
Samd21 Delay functions
M0 Pro
Is that an Arduino?
Yes, but I am using AS7 and I don't want to use the Arduino Library set. I most likely will get a SAM21 xplained pro, to learn how to program the SAMD21. Until then, I am using the Arduino M0 Pro.
If you are avoiding the Arduino Libraries, one wonders why you are concerned about software delay functions. Using hardware timers is a much better way to do timing in an application, and the SAMD21G has six timers in it.
That said, yes, there are times that busy waiting loops can be useful. Not having used the libraries myself ( on AS7, or the SAMD21 ), I can't help with locating them though.
Martin Jay McKee
The advantage with using an XPlained Pro board is that, when you plug it in, AS will recognise it and will give you the list of available examples - and that will include (at least) one using the ASF Delay Service ...
(I don't know how AS responds when your board is connected)
/* infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0484c/CHDCICDF.html //void DelayCycles(volatile U32 n){while(n--);} 00000320 <DelayCycles>: //uses 8 cycles on each loop iteration (on ARM Cortex M0+) 320: b082 sub sp, #8 322: 9001 str r0, [sp, #4] 324: 9b01 ldr r3, [sp, #4] 2 cycles (loop start) 326: 1e5a subs r2, r3, #1 1 cycle 328: 9201 str r2, [sp, #4] 2 cycles 32a: 2b00 cmp r3, #0 1 cycles 32c: d1fa bne.n 324 <DelayCycles+0x4> 2 cycles (branch to start) 32e: b002 add sp, #8 330: 4770 bx lr */ #define CYCLES_IN_DLYTICKS_FUNC 8 #define MS_TO_DLYTICKS(ms) (U32)(F_CPU / 1000 * ms / CYCLES_IN_DLYTICKS_FUNC) // ((float)(F_CPU)) / 1000.0 #define DelayTicks(ticks) {volatile U32 n=ticks; while(n--);}//takes 8 cycles #define DelayMs(ms) DelayTicks(MS_TO_DLYTICKS(ms))//uses 20bytes
here is a barebones Simple DelayMs(); routine...
Works well for even number frequency CPU, such as 8MHz, 48MHz, etc..
You can change MS_TO_DLYTICKS if you have an odd frequency CPU and need to prevent 32bit overflow/underflow
Inspect your LSS file to see if your cycles used is different, if it is, just update the define for it
here is a barebones Simple DelayMs(); routine..
Thanks
your welcome
You have to beware of the number of flash wait states for this solution.
I know, I tried to write it in "in line assembly" and kept getting a thumb16 error for opcode "subs". Which makes no sense since the LSS file shows the exact opcode being used without issue. If you have an inline assemly version for samd09 cortex m0+ or similar please do tell.
Here is some assembly code to use cycles for a delay in usecs for the Cortex M0+
#define F_CPU 8000000UL #if F_CPU == 8000000UL __attribute__ ( ( section ( ".ramfunc" ) ) ) void delay_usec ( uint32_t n ) { __asm ( "mydelay: \n" " sub r0, r0, #1 \n" // 1 cycle " nop \n" // 1 cycle " nop \n" // 1 cycle " nop \n" // 1 cycle " nop \n" // 1 cycle " nop \n" // 1 cycle " bne mydelay \n" // 2 if taken, 1 otherwise ); } #elif F_CPU == 48000000UL __attribute__ ( ( section ( ".ramfunc" ) ) ) void delay_usec ( uint32_t n ) { __asm ( "mydelay: \n" " mov r1, #15 \n" // 1 cycle "mydelay1: \n" " sub r1, r1, #1 \n" // 1 cycle " bne mydelay1 \n" // 2 if taken, 1 otherwise " sub r0, r0, #1 \n" // 1 cycle " bne mydelay \n" // 2 if taken, 1 otherwise ); } #else #error F_CPU is not defined #endif
In your code...
//... // Delay 1 millisecond delay_usec (1000); //...
If you want to use the SysTick for a delay see this post...
https://community.atmel.com/forum/d21xplain-simple-program-get-started
Regards,
-Chris
#define _DelayCycInAsm 6 #define _MsToTicks(ms) (U32)(F_CPU / 1000 * (ms) / _DelayCycInAsm) #define DelayMs(ms) _AsmDlyLoop(_MsToTicks(ms)) inline void _AsmDlyLoop(volatile U32 loopcnt) { asm volatile ( "mov r0, %0 \n" //load the initial loop counter "loop%=: \n" //loop start "DMB \n" //(data memory barriers (3 cycles) "sub r0, #1 \n" //subs does not work for thumbs16 mode, so use sub (1 cycle) //"nop \n" //in case you need to add more cycles, uncomment this "bne loop%= \n" //(2 cycle) : //empty output list : "r" (loopcnt) //input to the asm routine : "r0", "cc" //clobber list ); }
cwunder, I like your code... I came up with the above routine today...
Question....
How does the "uint32_t n" function parameter get used, I don't see it used anywhere in the assembly statement?
I'm not understanding how the "n" effects the duration
That is the value which is passed in R0 "Argument / result / scratch register 1".
It is your delay...
http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042f/IHI0042F_aapcs.pdf
...edit
This is a function call to SRAM so it is independent of flash wait states.
Ah gotcha, I get it now...
what about your loop label names, I thought you had to put "%=" after a loop name so that the compiler would make it a unique name?
evidently you don't need the "%=" the way you do it, I just tested and it works fine...
I figured out the below code is the equivalent of how it is done via ASF, just put into a file called "delay.h" for sec ms and us delay routines
#ifndef DELAY_H_HEADER #define DELAY_H_HEADER #define RAMFUNC __attribute__ ((section(".ramfunc"))) #define OPTIMIZE_HIGH __attribute__((optimize(s))) #define cpu_ms_2_cy(ms, f_cpu) (((uint64_t)(ms) * (f_cpu) + (uint64_t)(7e3-1ul)) / (U64)7e3) #define cpu_us_2_cy(us, f_cpu) (((uint64_t)(us) * (f_cpu) + (uint64_t)(7e6-1ul)) / (U64)7e6) #define delay_cycles portable_delay_cycles #define cpu_delay_s(delay) delay_cycles(cpu_ms_2_cy(1000 * delay, F_CPU)) #define cpu_delay_ms(delay) delay_cycles(cpu_ms_2_cy(delay, F_CPU)) #define cpu_delay_us(delay) delay_cycles(cpu_us_2_cy(delay, F_CPU)) #define _delay_us cpu_delay_us #define _delay_ms cpu_delay_ms #define _delay_s cpu_delay_s // Delay loop is put to SRAM so that FWS will not affect delay time OPTIMIZE_HIGH RAMFUNC void portable_delay_cycles(uint32_t n) { __asm ( "loop: DMB \n" #ifdef __ICCARM__ "SUBS r0, r0, #1 \n" #else "SUB r0, r0, #1 \n" #endif "CMP r0, #0 \n" "BNE loop " ); } #endif
I know this post is Old, but you must write thumb function before each ASM function or it will not compile. (in the .S file) Here an example of a Delay in ASM
.thumb_func SmallDelay: mydelay2: sub r0, r0, #1 nop.w nop.w nop.w cmp r0,#0 bne mydelay2 bx lr //Return
I hope it will help someone else.
Cedric