nanoseconds delay

Phil333
Fri May 12, 2017 8:31 am
Hello guys!

Today I am going to test my Maple Mini a little with my oscilloscope with the Arduino IDE.
If I want to check the fastes rate this device can give out HIGH and LOW levels, how can I do it?
I know of the delayMicroseconds() function but is there something faster like delayNanoseconds() or something similar that I can use ?

As output I want to use Pin3 / PB0 as this is able to generate PWM and should be fast enough using something like this:
void setup()
{
pinMode(3, OUTPUT);
}

void loop()
{
//some delay here
gpio_write_bit(GPIOB,0,HIGH); // D3 HIGH
//some delay here
gpio_write_bit(GPIOB,0,LOW); // D3 LOW
}


stevestrong
Fri May 12, 2017 8:34 am
Have you read this thread?

Phil333
Fri May 12, 2017 11:36 am
Now I have but I dindnt get it :D

stevestrong
Fri May 12, 2017 12:02 pm
Phil333 wrote:Today I am going to test my Maple Mini a little with my oscilloscope with the Arduino IDE.
If I want to check the fastest rate this device can give out HIGH and LOW levels, how can I do it?

racemaniac
Fri May 12, 2017 12:07 pm
how many of such signals do you need? if it’s only 1 or 2 pins, setting up an SPI DMA transfer would be the fastest :) (abusing the mosi pin for this purpose :) ). then comes the port manipulation via the registers & memory to memory dma as mentioned in that thread :)

Phil333
Fri May 12, 2017 12:38 pm
I just need one pin as output to do some speed measuring with my oscilloscope.

So I just need one pin to change at a variable time but as fast as possible.

As far as I understand I can use something like this:
void setup()
{
RCC_BASE->APB2ENR |= 0x10; // enable GPIOC clock
GPIOB->regs->CRL = (GPIOB->regs->CRL & 0xFFFFFFF0) | 0x00000003; //set PB0/Pin3 as output (max speed 50MHz)
}

void loop()
{
//Set Pin3 (HIGH)
GPIOB->regs->BSRR = 0b0000000000000001; //lower 16 bits
//Clear Pin3 (LOW)
GPIOB->regs->BRR = 0b0000000000000001; //lower 16 bits
}


racemaniac
Fri May 12, 2017 12:51 pm
what speed are you hoping to get? you can test that code, it’ll probably toggle the pin at a speed of a few Mhz.
you can insert some NOP instructions in between to slow it down:
__NOP ();

stevestrong
Fri May 12, 2017 1:11 pm
Wouldn’t be simpler to set up a timer to generate the signal?

Phil333
Fri May 12, 2017 1:13 pm
I hope to get the fastes speed possible to check how fast it can get and if the oscilloscope is able to measure it :)

I tested my code above and got a speed of ~36,2MHz.
Is anything faster possible?

I will attach a screenshot of it (I know my oscilloscope is overshooting but hey… it was just 200€ :D )

pic_25_1.jpg
pic_25_1.jpg (100.56 KiB) Viewed 2293 times

racemaniac
Fri May 12, 2017 1:29 pm
ugh, i had hoped the nop would work like that. a nop instruction is an instruction that does nothing and takes exactly 1 clock cycle :). search the forum a bit on how to get the NOP instruction working :).

if it’s already doing 36Mhz, then that’s pretty nice, the long delay between is the jump that’s being done for the loop.
faster than 36 Mhz is not possible, as your processor is running @72Mhz, and will need 1 clockcycle to turn the pin on, and one cycle to turn it off again :).

If you want a continuous pulse as someone mentioned, have a go at using a timer to toggle the pin and see how fast that can go :).


ag123
Fri May 12, 2017 2:42 pm
oh wow, didn’t realise ‘square’ wave at 36mhz looks like a wavy impulse at 36mhz. APB1 runs at max72 mhz, you may have maxed out what’s possible, unless erm overclock it :lol:

edogaldo
Fri May 12, 2017 4:24 pm
I think this could speed things up a bit more:
void loop()
{
while(1) {
//Set Pin0 (HIGH)
GPIOB->regs->BSRR = 0b0000000000000001; //lower 16 bits
//Clear Pin0 (LOW)
GPIOB->regs->BRR = 0b0000000000000001; //lower 16 bits
}
}

Phil333
Fri May 12, 2017 6:04 pm
Because you guys seems to be interessted in this stuff, I made a few more screenshots comparing the methods:

void loop()
{
//Set Pin3 (HIGH)
GPIOB->regs->BSRR = 0b0000000000000001; //lower 16 bits
//Clear Pin3 (LOW)
GPIOB->regs->BRR = 0b0000000000000001; //lower 16 bits
}


Phil333
Fri May 12, 2017 6:42 pm
PS: My Arduino Uno (5V 16MHz) can go faster compared to what its frequency is… I get 16MHz (16,5MHz to be true) impulses…

0001.jpg
0001.jpg (115.24 KiB) Viewed 431 times

ag123
Fri May 12, 2017 7:00 pm
in platforms.txt in the g++ and gcc compile lines instead of -Os (optimise size) change it to option -O2 (optimise more) lets see where it gets :lol:

the other way is unroll the loops e.g. but u’d get fast and slow spikes, and if u combine with -O2 the end result may be unpredictable, e.g. the compiler may ‘decide’ to do both 1’s first then do both 0’s. of course u could also unroll the loop many times, but u’d get fast, fast, fast, fast … slow (at the loop)

then there are shrewd gcc tricks to tweak branch prediction
http://blog.man7.org/2012/10/how-much-d … y-and.html

the ultimate optimization that gcc / g++ may do is that it ‘decides’ that all those things that you re doing make no sense and *remove* them
:lol:

void loop()
{
while(1) {
//Set Pin0 (HIGH)
GPIOB->regs->BSRR = 0b0000000000000001; //lower 16 bits
//Clear Pin0 (LOW)
GPIOB->regs->BRR = 0b0000000000000001; //lower 16 bits
//Set Pin0 (HIGH)
GPIOB->regs->BSRR = 0b0000000000000001; //lower 16 bits
//Clear Pin0 (LOW)
GPIOB->regs->BRR = 0b0000000000000001; //lower 16 bits
}
}


Pito
Fri May 12, 2017 8:04 pm
https://github.com/OliviliK/STM32F103/w … rial3_GPIO
Ollie is active here..

Leave a Reply

Your email address will not be published. Required fields are marked *