Sampling rate and ticks period

Hi, I am trying to sample a signal with a 2000 [Hz] sampling frequency. This all using an ESP32. But, always bug when I try to do it, even when I change the standard values of tick rate in the config.

Can I do that using freeRTOS or even any other idea to accomplish this?

One suggestion, DON’T try to make the basic tick rate be 2000 Hz (if you mean 2000 kHz, i.e 2 MHz, this is even more so).

Set up a hardware timer that gives you an interrupt at that rate and in the ISR record the signal, and after every ‘chunk’ that you record, signal a task to respond.

If it is an analog signal, try to have the timer directly signal the conversion, and respond to a conversion complete interrupt (many ADC can be set to auto sample at a defined rate).

Thank you, I think it’s gonna work. Yes, it’s an attempt to read an analog signal with a 2000 Hz rate. I will try this later and return here to feedback community. I bet that this is the question of a lot users trying to solve this type of case.

(I am sorry, I made a mistake in the original post, its not 2000 kHz, but 2000 Hz)

Yes, to read the ADC at 2000 Hz, you want to program it to auto sample at that rate (depending on the hardware, that may be a function in the ADC itself, or you need to tie it to a timer in the processor) and have an ISR receive the data from the ADC each time it is done, and wake up a task every N samples to process, depending on your need. This removes the jitter from trying to have the software create the sample period which will normally cause some problems.

I tried this code, but doesn’t work. For some reason i can’t decrease period time between samples to less than 0,667 [ms], even when i change the middle parameter in timerAlarmWrite. In this case i putted in 0,5 [ms]. What it could happen? Im thinking that it can be limited by the time of the execution in analogRead function, but i hope not.

#include <Arduino.h>
#include "esp_timer.h"

volatile int interruptCounter;

int totalInterruptCounter;

hw_timer_t * timer = NULL;

portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;

void IRAM_ATTR onTimer() {

  portENTER_CRITICAL_ISR(&timerMux);

  interruptCounter++;

  portEXIT_CRITICAL_ISR(&timerMux);

}

void setup() {

  Serial.begin(115200);

  timer = timerBegin(0, 80, true);

  timerAttachInterrupt(timer, &onTimer, true);

  timerAlarmWrite(timer, 500, true);

  timerAlarmEnable(timer);

}

void loop() {

  if (interruptCounter > 0) {

    portENTER_CRITICAL(&timerMux);

    interruptCounter--;

    Serial.println((analogRead(12)-1937)*0.681);    

    portEXIT_CRITICAL(&timerMux);

  }

}

You should tell what exactly doesn’t work means :wink: And also which MCU at which clock etc. you’re using.
Assuming you mean that the polling loop is slower than the interrupt rate if the time period gets too short I guess it’s caused by pretty time consuming Serial.println.
Related to this you should mention and consider the baud rate of your serial interface.
Is this some test code ? Signaling from an ISR to a task should be done using a polled variable. There are better and more suitable alternatives like FreeRTOS task notifications.

void setup() {
Serial.begin(115200);
timer = timerBegin(0, 80, true);
timerAttachInterrupt(timer, &onTimer, true);
timerAlarmWrite(timer, 1000000, true);
timerAlarmEnable(timer);
}

Yes, this code is just a prototype. I tried another code, but i got panic error in wdt. Even if Serial.println is taking some time, i will have to storage this data in some variable. So, this is a big limitation. I want to sampling with a 2kHz sampling rate at less using analogRead().

The difference between the two codes is that the first, that i posted here, do not have the panic error, and the second have this panic and is limited.

If you wanna see, there is the another code:

#include <Arduino.h>

/* create a hardware timer */
hw_timer_t * timer = NULL;

void IRAM_ATTR onTimer(){
  Serial.println(analogRead(12));
}

void setup() {
  Serial.begin(115200);

  pinMode(12, INPUT);

  /* Use 1st timer of 4 */
  /* 1 tick take 1/(80MHZ/80) = 1us so we set divider 80 and count up */
  timer = timerBegin(0, 80, true);

  /* Attach onTimer function to our timer */
  timerAttachInterrupt(timer, &onTimer, true);

  /* Set alarm to call onTimer function every second 1 tick is 1us
  => 1 second is 1000000us */
  /* Repeat the alarm (third parameter) */
  timerAlarmWrite(timer, 500, true);

  /* Start an alarm */
  timerAlarmEnable(timer);
  Serial.println("start timer");
}

void loop() {
    delay(10000);
}

Are you sure that Serial.println can be called in ISRs ? Usually it’s not possible and might cause the crash.
Often it’s possible to use an ADC with DMA to do the sampling in HW.
This might help. Good luck !

Yes, Its not possible that you call Serial.println in ISRs