SAM D10 pin toggling frequency

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

Hi,

I am working on a RGB Led matrix and fast toggling of IO pins matters to me.

I created a simple example project to blink the LED on SAM D10 mini Xplained board. This project uses internal 8Mhz. Then I modified the project just to toggle a pin (PA_10) in the while loop. I measured the frequency of the toggling pin and this is what I get:

toggling frequency image

I am expecting the frequency to be more or less 4Mhz (8Mhz/2 - since it's toggling). I tested the project with 48Mhz DFLL also and this is what I get on test pin:

pin toggling image

I want the toggling as fast as possible. Now the question is, if this is a normal behavior? Or if this has anything to do with internal comm bus (AHB)? Is it possible to change bus clock? How?

I have attached the project too, which I created in Atmel studio 6.2. Please review the project and tell me if I am doing it wrong.

Attachment(s): 

This topic has a solution.

BR / Yasir Qureshi

Last Edited: Thu. Oct 15, 2015 - 11:32 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Not sure about the D10 but if it has a DIV8 fuse in it like the AVR's then the upper trace is correct from what you described as your setup clock source wise.

 

I have no explanation as to what is going on in the bottom trace, other than possibly you are selecting the wrong internal clock(wild a## guess).

 

Jim

 

EDIT:

Again I am not very fluent in the SAM's as I am just starting with them but I looked at your project and I saw this in your conf_clocks.h file:

/* Configure GCLK generator 0 (Main Clock) */
#  define CONF_CLOCK_GCLK_0_ENABLE                true
#  define CONF_CLOCK_GCLK_0_RUN_IN_STANDBY        false
#  define CONF_CLOCK_GCLK_0_CLOCK_SOURCE          SYSTEM_CLOCK_SOURCE_OSC8M       ;<-------This might be the problem for trace #2
#  define CONF_CLOCK_GCLK_0_PRESCALER             1
#  define CONF_CLOCK_GCLK_0_OUTPUT_ENABLE         false

For the second scope trace it shows a frequency of 4Mhz so if your internal main clock is running at 8Mhz then the toggle output frequency would be 8Mhz/2 = 4Mhz.

 

I might be wrong on this.

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

Last Edited: Thu. Sep 24, 2015 - 05:25 PM
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

For the best performance to the Port I/O you should use the PORT_IOBUS path.

 

In your example you need to consider the execution time of the instructions. At 8MHz this 125nsec per clock so the toggle can occur every cycle but is not practical.

 

Extending your example and enabling the clock output to decode the instruction provide the following, that one cycle to toggle the port pin and two cycles for the branch.

while (true) {
    //port_pin_toggle_output_level(TEST_PIN);
    PORT_IOBUS->Group[0].OUTTGL.reg = PORT_PA10;
    PORT_IOBUS->Group[0].OUTTGL.reg = PORT_PA10;
    PORT_IOBUS->Group[0].OUTTGL.reg = PORT_PA10;
    PORT_IOBUS->Group[0].OUTTGL.reg = PORT_PA10;
}

The disassembly

    PORT_IOBUS->Group[0].OUTTGL.reg = PORT_PA10;
00000180   str	r2, [r3, #28]		 
    PORT_IOBUS->Group[0].OUTTGL.reg = PORT_PA10;
00000182   str	r2, [r3, #28]		 
    PORT_IOBUS->Group[0].OUTTGL.reg = PORT_PA10;
00000184   str	r2, [r3, #28]		 
    PORT_IOBUS->Group[0].OUTTGL.reg = PORT_PA10;
00000186   str	r2, [r3, #28]		 
00000188   b	#-12	

Blue trace is the CPU clock

Red is pin PA10

 

Hope that helps,

-Chris

Last Edited: Thu. Sep 24, 2015 - 06:03 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

you should use the PORT_IOBUS path.

While the ASF  port_pin_toggle_level() function is nicely inline, causing the while loop to produce nicely minimal code:

 

port_pin_toggle_output_level(LED_0_PIN);

 818:    61d3          str    r3, [r2, #28]
 81a:    e7fd          b.n    818 <main+0x60>

It does NOT use the PORT_IOBUS path (it uses the slower APB path...)

(I wonder why?)

 

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

Hi Jim,
Attached project is configured to use internal 8mhz clock. While second trace is done with 48mhz DFLL just to test if this makes any difference. But it was still ~8 times slower.

BR / Yasir Qureshi

Last Edited: Thu. Sep 24, 2015 - 08:49 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yasir,

Like I said, I am not the best source of a solution on these parts as I am just getting into them, but when I looked at your project that jumped out at me.  Sorry it was of no help to you.

 

Hell I would not mind a cheat sheet on the D10 and the D21 explaining some of the peripherals like the clocks, I/O and such as the help files are not so helpful and the datasheets are thicker than an encyclopedia.

 

Cheers,

JIm

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

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

The thing to remember is that on the Cortex, the gpio is a peripheral vs devices like the AVR where there are specific instructions and the i/o is tightly coupled. To read or write a memory address (gpio appears as memory as does everything else) you need to:

load a register with the address of the peripheral. The ARM Cortex M0 has no 32 bit immediate load, so this is done via a literal pool - the address is stored in memory close by and the load is done pc relative.

load another register with the value (to write)

do a load or store

 

This all takes a few cycles. Note that once you've loaded the peripheral address into a register, you can keep using this, so subsequent accesses are faster.

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

Although even on the Cortex M0, SRAM and peripherals have separate busses, and there is an additional direct bus to GPIO that Chris mentions.

 

However, I don't think you can get around the addressing limitations of Thumb2, for any general IO you need 3 instructions to toggle an IO. For a specific port, and a specific frequency, some hand coded assembler can achieve that.

 

I am just doing some LED stuff with the D10 Xplained, just 3 LEDS though. I am curious for an LED matrix just how fast you need to toggle the IO?

Bob. Engineer and trainee Rocket Scientist.

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

Just a comment for controlling up to 4 LED's on the SAMD10. You can use the TCC peripheral to perform this with hardware such that you can have 16-bit resolution using a 16MHz clock (48MHz/3) to provide a period of 244Hz. The TCC has 4 Independent shadowed compare channels to control the duty cycle for each LED.

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

I am toggling the io pin as suggested by Chris using PORT_IOBUS path. And this helped me significantly. Thanks Chris.

while (true) {
    PORT_IOBUS->Group[0].OUTTGL.reg = PORT_PA10;
}

 

Here is what I get on my oscilloscope when I use 8Mhz internal clock (OSC8M):

8Mhz

 

This is just fine because when I turn on DFLL 48Mhz and choose main clock as DFLL then I get this:

image_4Mhz_after_48MhzDFLL

 

Above toggling frequency with DFLL selected would work perfectly for me right now.

And for those who wonder what RGB matrix am I using? here is the link: RGB LED Panel - 32x32

 

Thanks everyone for support and not letting me feel lost! wink

 

BR / Yasir Qureshi