Page 1 of 1

Creating accurate delay between 2 pulses on different pins.

Posted: Mon Dec 12, 2022 11:53 am
by Voidim
Greetings, i
am new to the esp32. At first glance i though that 240mhz can get me really accurate delays, but turns out it uses 80mhz timer clock, and i have to use divider = 2 so it is 40mhz at the end(25ns each clock), and i cant make my code work.

I have a esp-wroom-32 module(esp32 dev module) and use arduino IDE, my task is to generate 2 pulses on different pins with as much accuracy as possible:
1) make GPIO_NUM_2 and GPIO_NUM_4 go HIGH
2)Generate single shot pulses on a button press with predefined delay:
2.1) Generate negative pulse ~100nS on pin 2 (after that pulse pin2 stays HIGH)
2.2) Wait certain amount of uS: from 3uS to 35uS with precise accuracy.(30nS or less each step i want to increase or decrease delay)
(like to
2.3)Generate another ~100nS pulse on pin4 (after that pulse pin4 stays HIGH)

Currently i came up with the following test code using a timer, but for some reason it does not works as i want:
1)it does not increment delay by 25ns each time (but it starts to work a little better at 22uS or more)
2) minimum delay is ~6.6us, after a while it jumps to 7.7 etc
  1. #include "driver/timer.h"
  2. int i = 0; // value added to match each loop
  3.  
  4. static bool IRAM_ATTR onTimer(void *args) //ISR function
  5. {
  6. //2nd signal pulse
  7.   REG_WRITE(GPIO_OUT_W1TC_REG, BIT4); //GPIO4 LOW(CLEAR)
  8.   __asm__ __volatile__ (
  9.     " nop\n"
  10.     " nop\n"
  11.     " nop\n"
  12.     " nop\n"
  13.     " nop\n"
  14.     " nop\n"
  15.     " nop\n"
  16.     " nop\n"
  17.     " nop\n"
  18.     " nop\n"
  19.     " nop\n"
  20.     " nop\n"
  21.     " nop\n"
  22.     " nop\n"
  23.     " nop\n"
  24.     " nop\n"
  25.     " nop\n"
  26.     " nop\n"
  27.   );
  28.   REG_WRITE(GPIO_OUT_W1TS_REG, BIT4); //GPIO4 HIGH (SET) !!!!!!!!!!!!!!
  29.   timer_pause(TIMER_GROUP_0, TIMER_0);
  30.   return false;
  31. }
  32.  
  33. void setup() {
  34. ////TIMERS SETUP////
  35.   timer_config_t config = {
  36.     .alarm_en = TIMER_ALARM_EN, //ISR on
  37.     .counter_en = TIMER_PAUSE, //timer off after init
  38.     //.intr_type = TIMER_INTR_LEVEL, //can be ignored
  39.     .counter_dir = TIMER_COUNT_UP, //up
  40.     .auto_reload = TIMER_AUTORELOAD_EN, /hardware will load counter value after an alarm event;
  41.     .divider = 2, //from 2 to 65536 if 2  = 40mhz =25ns
  42.   }; //default clock source is APB (80mhz)
  43.  
  44.  timer_init(TIMER_GROUP_0, TIMER_0, &config); //init
  45. timer_set_counter_value(TIMER_GROUP_0, TIMER_0, 0); //start value
  46. timer_set_alarm_value(TIMER_GROUP_0, TIMER_0, 250); //match value
  47. timer_isr_callback_add(TIMER_GROUP_0, TIMER_0, onTimer, NULL, 0); // add isr func
  48.  timer_enable_intr(TIMER_GROUP_0, TIMER_0); // enable isr
  49.  
  50. ////PINS SETUP////
  51. //set it as gpio
  52. gpio_pad_select_gpio( GPIO_NUM_2);
  53.  gpio_pad_select_gpio( GPIO_NUM_4);
  54. //output
  55. gpio_set_direction( GPIO_NUM_2,  GPIO_MODE_OUTPUT);
  56.   gpio_set_direction( GPIO_NUM_4,  GPIO_MODE_OUTPUT);
  57. //pullup to 3.3
  58. gpio_set_pull_mode( GPIO_NUM_2,  GPIO_PULLUP_ONLY);
  59.   gpio_set_pull_mode( GPIO_NUM_4,  GPIO_PULLUP_ONLY);
  60. //out current = 40ma
  61. gpio_set_drive_capability( GPIO_NUM_2,  GPIO_DRIVE_CAP_3);
  62.   gpio_set_drive_capability( GPIO_NUM_4,  GPIO_DRIVE_CAP_3);
  63. //set as high
  64. gpio_set_level( GPIO_NUM_2,  1); //HIGH
  65.   gpio_set_level( GPIO_NUM_4,  1); //HIGH
  66. }
  67.  
  68. void loop() {
  69. delay(500);
  70.  timer_set_alarm_value(TIMER_GROUP_0, TIMER_0, 100+i); //set new match value (100 should be ~2.5uS)
  71. timer_set_counter_value(TIMER_GROUP_0, TIMER_0, 0); //reset starting value to 0
  72. delay(50);
  73.  
  74. //1st signal PULSE
  75.  REG_WRITE(GPIO_OUT_W1TC_REG, BIT2); //GPIO2 LOW(CLEAR)
  76.  __asm__ __volatile__ (
  77.     " nop\n"
  78.     " nop\n"
  79.     " nop\n"
  80.     " nop\n"
  81.     " nop\n"
  82.     " nop\n"
  83.     " nop\n"
  84.     " nop\n"
  85.     " nop\n"
  86.     " nop\n"
  87.     " nop\n"
  88.     " nop\n"
  89.     " nop\n"
  90.     " nop\n"
  91.     " nop\n"
  92.     " nop\n"
  93.     " nop\n"
  94.     " nop\n"
  95.   );
  96.   REG_WRITE(GPIO_OUT_W1TS_REG, BIT2); //GPIO2 HIGH (SET)
  97.  
  98. //start timer
  99.   timer_start(TIMER_GROUP_0, TIMER_0);
  100. }

Maybe there is better peripheral to do that task?
There is so many ways it seems to do that task: with DMA, RTC, LED pwm, creating some assembly code(i am not familiar with it) that can utilize 240mhz so we can get 4.16ns step.
All those ways just overwhelms me.