Delay less than 1 µs ?

Post here first, or if you can't find a relevant section!
User avatar
Rick Kimball
Posts: 1058
Joined: Tue Apr 28, 2015 1:26 am
Location: Eastern NC, US
Contact:

Re: Delay less than 1 µs ?

Post by Rick Kimball » Tue Nov 07, 2017 4:34 pm

You should search in code snippets for a post I made about using the DWT peripheral for cycle counting
-rick

User avatar
Rick Kimball
Posts: 1058
Joined: Tue Apr 28, 2015 1:26 am
Location: Eastern NC, US
Contact:

Re: Delay less than 1 µs ?

Post by Rick Kimball » Tue Nov 07, 2017 11:34 pm

I used Pito's code to create a 100kHz toggle using the DWT timer. Granted you aren't going to be able to create a 10nsec pulse, as the the cycle count at 72 MHz is 13.888 nsec, however you can do accurate usec pulses using the DWT peripheral.

Code: Select all

// accurate micro second pin toggle ..
// DWT defines from Pito's post
// * note, I made CpuGetTicks volatile

#define DWTEn()         (*((uint32_t*)0xE000EDFC)) |= (1<<24)
#define CpuTicksEn()    (*((uint32_t*)0xE0001000)) = 0x40000001
#define CpuTicksDis()   (*((uint32_t*)0xE0001000)) = 0x40000000
#define CpuGetTicks()   (*((volatile uint32_t*)0xE0001004))

void setup() {
  DWTEn();
  CpuTicksEn();
  pinMode(LED_BUILTIN,OUTPUT); // for blue pill this is the PC13
}

const uint32_t usec_delay = 5; // 5usecs == 100kHz toggle
const unsigned usecs_in_cycles = 72*usec_delay; // 72 cycles in 1 usec with 72MHz system clock

void loop() {
  static unsigned toggle;
  static uint32_t prev;

  while(1) {
    uint32_t curr = CpuGetTicks();

    // toggle LED pin every usec_delay
    if ( (curr-prev) >= usecs_in_cycles  ) {
      prev = prev + usecs_in_cycles;
      toggle^=1;
      GPIOC->regs->BSRR = ((1 << 13 ) << 16) | (toggle << 13);
    }
  }
}
-rick

edogaldo
Posts: 285
Joined: Fri Jun 03, 2016 8:19 am

Re: Delay less than 1 µs ?

Post by edogaldo » Wed Nov 08, 2017 11:14 am

acronis wrote:
Tue Nov 07, 2017 2:06 pm
you commented out "nop"

loop ()
{
digitalWrite(PA5,LOW);
//asm volatile ("nop");
digitalWrite(PA5, HIGH);
}

the time remains the same - 200 ns at the switching state on pine (((
If you want to achieve clock level speed you need to go with assembly..
Here a sample asm sketch to toggle PA5 on F407:

Code: Select all

void setup() {
  // put your setup code here, to run once:
  pinMode(PA5,OUTPUT);
  //GPIOA.regs->BSRRL = 0x0005;
  //GPIOA.regs->BSRRL = 0x0500;
  asm volatile ("mov r0,#0x0018");
  asm volatile ("movt r0,#0x4002");
  asm volatile ("mov r1,#0x0005");
  asm volatile ("mov r2,#0x0500");
  asm volatile ("myloop: strh r1, [r0]");
  asm volatile ("strh r2, [r0]");
  asm volatile ("strh r1, [r0]");
  asm volatile ("strh r2, [r0]");
  asm volatile ("strh r1, [r0]");
  asm volatile ("strh r2, [r0]");
  asm volatile ("strh r1, [r0]");
  asm volatile ("strh r2, [r0]");
  asm volatile ("strh r1, [r0]");
  asm volatile ("strh r2, [r0]");
  asm volatile ("strh r1, [r0]");
  asm volatile ("strh r2, [r0]");
  asm volatile ("strh r1, [r0]");
  asm volatile ("strh r2, [r0]");
  asm volatile ("strh r1, [r0]");
  asm volatile ("strh r2, [r0]");
  asm volatile ("strh r1, [r0]");
  asm volatile ("strh r2, [r0]");
  asm volatile ("b.n myloop");
}

void loop() {
  // put your main code here, to run repeatedly:

}
This is probably the fastest performance you can get and at this level you can better evaluate the difference of introducing an asm "nop"..

Cheers, E.
Last edited by edogaldo on Wed Nov 08, 2017 1:18 pm, edited 1 time in total.

acronis
Posts: 144
Joined: Thu Mar 02, 2017 12:32 pm

Re: Delay less than 1 µs ?

Post by acronis » Wed Nov 08, 2017 12:17 pm

YOU very much.
I will try to do so

edogaldo
Posts: 285
Joined: Fri Jun 03, 2016 8:19 am

Re: Delay less than 1 µs ?

Post by edogaldo » Wed Nov 08, 2017 1:18 pm

acronis wrote:
Wed Nov 08, 2017 12:17 pm
YOU very much.
I will try to do so
Sorry, I made a mistake with setting BSRR..
Here a correction anyway I'm not able to test it on the F407 so I cannot guarantee there are no more errors:

Code: Select all

void setup() {
  // put your setup code here, to run once:
  pinMode(PA5,OUTPUT);
  //GPIOA.regs->BSRR = 0x0020; // set PA5
  //GPIOA.regs->BSRR = 0x00200000; // clear PA5
  asm volatile ("ldr r0,#0x40020018"); // r0 -> GPIOA.regs->BSRR
  asm volatile ("mov r1,#0x0020"); // r1 -> mask to set PA5 HIGH in BSRR
  asm volatile ("lsl r2,r1,#0x10"); // r2 -> mask to set PA5 LOW in BSRR
  for(;;)
  {
    asm volatile ("str r2, [r0]");
    asm volatile ("str r1, [r0]");
    asm volatile ("str r2, [r0]");
    asm volatile ("str r1, [r0]");
    asm volatile ("str r2, [r0]");
    asm volatile ("str r1, [r0]");
    asm volatile ("str r2, [r0]");
    asm volatile ("str r1, [r0]");
    asm volatile ("str r2, [r0]");
    asm volatile ("str r1, [r0]");
    asm volatile ("str r2, [r0]");
    asm volatile ("str r1, [r0]");
    asm volatile ("str r2, [r0]");
    asm volatile ("str r1, [r0]");
    asm volatile ("str r2, [r0]");
    asm volatile ("str r1, [r0]");
  }
}

void loop() {
  // put your main code here, to run repeatedly:

}

Post Reply