2
\$\begingroup\$

I have a very simple C program that toggles a pin on a Cortex-M3 board (SAM3X8E) with a 84MHz clock speed. I built this using Atmel Studio 6.1.

#include <asf.h>

int main (void)
{
    board_init();
    PIOB->PIO_PER = PIO_PB27;  //Enable PIO
    PIOB->PIO_OER = PIO_PB27;  //Set to OUTPUT
    PIOB->PIO_PUDR = PIO_PB27; //Disable the pull up resistor

    while(1) {
        PIOB->PIO_SODR = PIO_PB27; //Enable output
        PIOB->PIO_CODR = PIO_PB27; //Disable output
    }
}

Now when I load this onto the board, and hook up an oscilloscope up to the pin, I see the signal pulsating at about 700kHz. I would have thought that the speed of the cycle would have been much quicker with this minimalistic code.

Is it possible to get a GPIO frequency higher than a MHz using this setup? Is it my build environment that is not producing optimal code? Is it possible to get faster GPIO using another technique?

\$\endgroup\$
4
  • 1
    \$\begingroup\$ Are you sure your processor is actually clocking at 84 MHz? Most don't on boot, but only after you select an oscillator, enable a PLL or the like, even configure memory timings. Also make sure your scope is legitimately able to measure these speeds, and not aliasing them to lower frequencies. On the software side, learn how to dump out the assembly or machine code resulting from compiling your program - one would think that what you have would compile to relatively few instructions, but proof would be good. \$\endgroup\$ May 17, 2013 at 14:55
  • \$\begingroup\$ Chris, I'm using a Due and just programming it using the Atmel suite, so I have to take it on their word that it is clocked to 84MHz (or at least capable of it). The scope is a 200MHz so it should be able to detect the oscillations of the GPIO pins. I'll give the dump to assembly a go, and see if there is something obvious. As for your first three suggestions, how do I enable a PLL or configure memory timings? \$\endgroup\$
    – W Devauld
    May 17, 2013 at 20:07
  • \$\begingroup\$ Find the source of the Arduino runtime initialization/support stuff and see what they do. Or find reference code from Atmel. \$\endgroup\$ May 17, 2013 at 21:41
  • 1
    \$\begingroup\$ Check out: kerrywong.com/2014/09/21/on-arduino-due-pwm-frequency Kerry does the same thing, but with Arduino code. Got to 16MHz before switching to PWM mode, managed to get to 84MHz. \$\endgroup\$ Sep 30, 2014 at 7:54

3 Answers 3

6
\$\begingroup\$

I don't know the SAM3X family but the Atmel Studio IDE and the UC3 Family from Atmel.

Try adding the Clock Module to your project, configure it via the config_clock.h file, then add a sysclk_init() call to your main and it should be going a lot faster.

The SAM3X by default clocks at 4MHz if I'm not mistaken.

\$\endgroup\$
0
\$\begingroup\$

Try using direct port access and not like you did via the PIO struct. Also enable the OWER flag for your PIO pins and write your state directly to REG_PIOX_ODSR which saves you some extra instructions and improves the overall speed of your code. Your code could look similar to this:

int main (void)
{
    board_init();
    sysclk_init();
    PIOB->PIO_PER = PIO_PB27;  //Enable PIO
    PIOB->PIO_OER = PIO_PB27;  //Set to OUTPUT
    PIOB->PIO_OWER = PIO_PB27; //Enable direct bit set

    while(1) {
        REG_PIOB_ODSR = (~(REG_PIOB_ODSR & PIO_PB27)) & PIO_PB27; //Enable output
    }
}

If you want to go even faster try to use timer interrupts which can handle speeds to half the clock speed of the cpu in the case of the sam3x up to 42MHz

\$\endgroup\$
1
  • 2
    \$\begingroup\$ Not sure how an ISR can beat a simple write (which is maybe 2 cycles if you're lucky). Writing alternate 1/0 is faster than read, invert, write by a good margin though. \$\endgroup\$ Dec 31, 2016 at 19:23
-1
\$\begingroup\$

Remember the while loop itself would have some impact too. A good way to minimize the impact of this is to duplicate the meat of the action (actually setting the pins) a few hundred times.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Not to any significant degree. A while(1) loop should compile to a single branch instruction. \$\endgroup\$
    – user39382
    Dec 31, 2016 at 19:11
  • \$\begingroup\$ Duplication like this is only sensible when your need is "bursty" - what you propose here would just make the output irregular. Besides the real problem was recognized long before you posted. \$\endgroup\$ Dec 31, 2016 at 19:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.