Samd21 Delay functions

Go To Last Post
16 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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.

"When all else fails, read the directions"

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

PhillyNJ wrote:
M0 Pro

Is that an Arduino?

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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.

"When all else fails, read the directions"

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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

As with most things in engineering, the answer is an unabashed, "It depends."

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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)

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
/*
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

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

12oclocker wrote:
here is a barebones Simple DelayMs(); routine..

Thanks

"When all else fails, read the directions"

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

your welcome yes

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You have to beware of the number of flash wait states for this solution.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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

Last Edited: Sat. Jan 2, 2016 - 11:26 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
#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

 

Last Edited: Sat. Jan 2, 2016 - 11:34 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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.

Last Edited: Sat. Jan 2, 2016 - 11:51 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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?

Last Edited: Sun. Jan 3, 2016 - 06:29 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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