GPIO Clock

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
Not applicable
Hello,

I'm using the XMC1302 Microcontroller for a BLDC Motor Control.
The clock of the controller ist set up with SystemInit to 32Mhz.

Now I have written a little function for a 1us delay.
To measure the time i use a GPIO Port.

void delay1us(void)

/*Turn LED on*/
PORT0->OUT |= 1<<12;

volatile uint16_t a;
for(a=0; a<1; a++);

/*Turn LED off*/
PORT0->OUT &= ~(1<<12);

With this code i measure a time of 1,7us.

/*Turn LED on*/
PORT0->OUT |= 1<<12;

/*Turn LED off*/
PORT0->OUT &= ~(1<<12);

With this code, I measure a time of 564ns.

Why ist this time so long when the clock ist set up to 32Mhz and the cycle time is 31ns?

Thanks for Your Response!
0 Likes
6 Replies
Not applicable
Are you running code out of FLASH space or out of RAM? You will come very close to 32 MIPS with a base clock of 32MHz if your code is run out RAM.

As a side note, I am highly confident setting GPIO is essentially a two step process. Please forgive me if I use the wrong terminology,...port access is much like a shadow register. First, you set the register to the value you want (1<<12), then you commit/latch the register value to the actual port hardware.

I think your 1.7uSec and 564nSec discrepancies are related to the wait states associated with M0 cortex based devices and how port access is handled. You could also check the optimization level. Is it set to -O3 for speed?

Steve.
0 Likes
Not applicable
Hi Steve,

Thanks for Your response!
With optimization level -O3 and with the OMR Register i can reduce the time from 564ns to 240ns.
That's a good improvement.

I don't know if the code is running out of flash or ram.
I think the porgramm code is stored on flash.

Subsequent the code that is running on the controller:

int main(void)
{
SystemInit();

PORT0->IOCR12 |= 1<<7;

PORT0->OMR |= 1<<12;
PORT0->OMR |= 1<<28;

while(1U)
{

}
}

So the conclusion is, that the maximum speed to toggle a gpio port is 240ns.
So you think thats normal for a cortex M0 device?


Denis
0 Likes
Not applicable
By the way, have you studied the disassembly to get a feel for how many actual instructions your 1302 is trying to execute? Anyway, {anybody reading my response, please, PATIENTLY correct me} the flash of M0 cortex devices require a wait state between each executed command. With that in mind, I think both of your lines of code that access the OMR register are really two instructions, which immediately gives you four RISC instructions. Each RISC instruction has a wait state, which finally gives you 4 X 2 = 8 clock cycles. The reciprocal of (240nSec / 8 clock cycles) is VERY close to 32MHz.

Run as much code as possible out of RAM if you want full speed. Consider the following:


void ToggleTheBit(void) __attribute__ ((section (".ram_code")));

void ToggleTheBit(void)
{
PORT0->OMR |= 1<<12;
PORT0->OMR |= 1<<28
}


I believe this code might execute in ~120nSec.

Steve.
0 Likes
Not applicable
Thanks for your explanation.
I have tested your programm code, but there is no improvement. The time is still 240ns.


void ToggleTheBit(void) __attribute__ ((section (".ram_code")));

void ToggleTheBit(void)
{
PORT0->OMR |= 1<<12;
PORT0->OMR |= 1<<28;
}

int main(void)
{
SystemInit();

PORT0->IOCR12 |= 1<<7;

ToggleTheBit();

while(1U)
{

}
}


The disassemly code from the compiler is:


main:
1000115c: push {r3, lr}
29 SystemInit();
1000115e: bl 0x10001138
31 PORT0->IOCR12 |= 1<<7;
10001162: movs r2, #128 ; 0x80
10001164: ldr r3, [pc, #28] ; (0x10001184
)
10001166: ldr r1, [r3, #28]
10001168: orrs r2, r1
23 PORT0->OMR |= 1<<12;
1000116a: movs r1, #128 ; 0x80
1000116e: ldr r2, [r3, #4]
10001170: lsls r1, r1, #5
10001172: orrs r2, r1
24 PORT0->OMR |= 1<<28;
10001174: movs r1, #128 ; 0x80
23 PORT0->OMR |= 1<<12;
10001176: str r2, [r3, #4]
24 PORT0->OMR |= 1<<28;
10001178: ldr r2, [r3, #4]
1000117a: lsls r1, r1, #21
1000117c: orrs r2, r1
1000117e: str r2, [r3, #4]
44 }


I'm not good in reading assembler code, but i think that are too much commands for toggeling a register.
0 Likes
jferreira
Employee
Employee
10 sign-ins 5 sign-ins First like received
Hi,

The OMR register is a write only register, you do not need to do a read modify operation and writting zeros will not affect the state of the other pins, just
void ToggleTheBit(void)
{
PORT0->OMR = 1<<12;
PORT0->OMR = 1<<28;
}


Regards,
Jesus
0 Likes
Not applicable
Hi Jesus,

thanks! With this time i get 156ns.

By the way, it is not necessary to write the code in RAM.

It will also execute in 156ns without "__attribute__ ((section (".ram_code")))"

Regards
Denis
0 Likes