But we have a problem that we cannot solve. ESP32 loses some of the pulses, which is why it is not possible to perform accurate measurements. The measurement time varies in the wide range that is not acceptable for the required accuracy. Measurement of pulses from a radio transmitter using an oscilloscope showed their high stability (0.1V / 3.3V, flat edges, 1.066666 MHz). At the same time, there are no problems with measuring pulses from GPS. Jitter is about 10 ESP32 cycles, which is enough for the necessary accuracy.
We used "driver/pcnt.h" to count pulses from the radio transmitter. In conjunction with the ISR. The PCNT counted 10,000 (int16_t counter) samples and caused an interrupt. The interrupt counted 100 samples, recording the ESP tick (XTHAL_GET_CCOUNT) of the first and last samples. The output from the radio transmitter used to generate the pulses is connected to GPIO_NUM_34 ESP32.
We will be very grateful for your advice on how to solve this problem.
- volatile uint32_t xthal1 = 0;
- volatile static uint32_t xthal_counter = 0;
- static void IRAM_ATTR Radio_CAL_ISR_handler(void* arg)
- {
- static BaseType_t xHigherPriorityTaskWoken = pdFALSE;
- static uint32_t xthal_val = 0;
- xthal_val = XTHAL_GET_CCOUNT();
- PCNT.int_clr.val = 1;
- if (xthal_counter == 0) {
- xthal1 = xthal_val;
- } else {
- if (xthal_counter >= 100)
- {
- pcnt_counter_pause(((Radio_device_t*)arg)->pcnt_unit);
- ((Radio_device_t*)arg)->cal_xthal = xthal_val - xthal1;
- xSemaphoreGiveFromISR( ((Radio_device_t*)arg)->Cal.sem, &xHigherPriorityTaskWoken );
- if( xHigherPriorityTaskWoken != pdFALSE ) { portYIELD_FROM_ISR(); }
- }
- }
- ++xthal_counter;
- }
- void Radio_PCNT_init(Radio_device_t* device)
- {
- pcnt_config_t pcnt_config = {
- // Set PCNT input signal and control GPIOs
- .pulse_gpio_num = device->DIO0_pin,
- .ctrl_gpio_num = PCNT_PIN_NOT_USED,
- .channel = device->pcnt_channel,
- .unit = device->pcnt_unit,
- // What to do on the positive / negative edge of pulse input?
- .pos_mode = PCNT_COUNT_INC, // Count up on the positive edge
- .neg_mode = PCNT_COUNT_DIS, // Keep the counter value on the negative edge
- // What to do when control input is low or high?
- .lctrl_mode = PCNT_MODE_KEEP, // Reverse counting direction if low
- .hctrl_mode = PCNT_MODE_KEEP, // Keep the primary counter mode if high
- // Set the maximum and minimum limit values to watch
- .counter_h_lim = 10000,
- .counter_l_lim = 0,
- };
- /* Initialize PCNT unit */
- pcnt_unit_config(&pcnt_config);
- /* Initialize PCNT's counter */
- pcnt_counter_pause(device->pcnt_unit);
- pcnt_counter_clear(device->pcnt_unit);
- /* Configure and enable the input filter */
- // pcnt_set_filter_value(device->pcnt_unit, 20);
- // pcnt_filter_enable(device->pcnt_unit);
- pcnt_event_enable(device->pcnt_unit, PCNT_EVT_H_LIM);
- device->Cal.counter = 0;
- device->cal_xthal = 0;
- /* Register ISR handler and enable interrupts for PCNT unit */
- // I tried levels above 3, but it does not work with them, the semaphore task does not receive
- pcnt_isr_register(&Radio_CAL_ISR_handler, device, ESP_INTR_FLAG_LEVEL3, &device->pcnt_isr_handle_Dio0);
- pcnt_intr_enable(device->pcnt_unit);
- /* Everything is set up, now go to counting */
- pcnt_counter_resume(device->pcnt_unit);
- }
- void Radio_cal_task (void *pvParameters)
- {
- Radio_device_t* device = pvParameters;
- xSemaphoreTake( device->Cal.sem, 0);
- device->cal_xthal = 0;
- if (xSemaphoreTake(device->Cal.sem, pdMS_TO_TICKS(5000)) != pdTRUE )
- {
- ESP_LOGE(TAG, "Calibration timeout error");
- }
- pcnt_counter_pause(device->pcnt_unit);
- pcnt_event_disable(device->pcnt_unit, PCNT_EVT_H_LIM);
- pcnt_intr_disable(device->pcnt_unit);
- esp_intr_free(device->pcnt_isr_handle_Dio0);
- double freq = (double)device->cal_xthal / (240000000 + 0);
- freq = freq / 100 / 10000 / 30;
- freq = 1 / freq;
- printf("Radio XTHAL diff: %u; ISR counter: %u; Freq: %.3f\n", device->cal_xthal, xthal_counter, freq);
- vTaskDelete(NULL);
- }
Result (the calculated frequency should be in the region of 32 MHz +- 500 Hz, XTHAL diff: 240,000,000 +- 3750):
Radio XTHAL diff: 275949921; ISR counter: 101; Freq: 26091690.746
Radio XTHAL diff: 276206703; ISR counter: 101; Freq: 26067433.997
Radio XTHAL diff: 277011921; ISR counter: 101; Freq: 25991661.204
Radio XTHAL diff: 276995640; ISR counter: 101; Freq: 25993188.918
Radio XTHAL diff: 277033722; ISR counter: 101; Freq: 25989615.806