ESP32 C6 PCNT
Posted: Sat Jun 29, 2024 7:44 am
Hello, I'm using a pcnt to count pules from a 10mhz ocxo. I get pretty stable results using a gps pps, sometimes 9,999,999 instead of 10 million but thats acceptable. But sometimes after about 1 minute I get a reading thats off by like 40000 pulses (approx), two readings off like this so 2 seconds and then it stabilizes to a new value. I guess there's something else goin on in the background that gets priority over my counter? How can I prevent this? I want to use the ocxo for accurate time keeping. To do this I mainly edited the pcnt example from esp itself. Do i need an esp32 with a second core to just make it count pulse? What do you suggest?
Thanks in advance.
Thanks in advance.
Code: Select all
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "esp_log.h"
#include "driver/pulse_cnt.h"
#include "driver/gpio.h"
#include "esp_sleep.h"
static const char *TAG = "example";
#define EXAMPLE_PCNT_HIGH_LIMIT 32000
#define EXAMPLE_PCNT_LOW_LIMIT -32000
#define EXAMPLE_EC11_GPIO_A GPIO_NUM_13
#define EXAMPLE_GPIO_INTERRUPT_PIN GPIO_NUM_10
int pulse_count = 0;
static int overflow_count = 0;
static void IRAM_ATTR gpio_isr_handler(void *arg)
{
pcnt_unit_get_count((pcnt_unit_handle_t)arg, &pulse_count);
int total_count = pulse_count + (overflow_count * EXAMPLE_PCNT_HIGH_LIMIT);
ets_printf("Total count: %d\n", total_count);
}
static bool example_pcnt_on_reach(pcnt_unit_handle_t unit, const pcnt_watch_event_data_t *edata, void *user_ctx)
{
BaseType_t high_task_wakeup;
QueueHandle_t queue = (QueueHandle_t)user_ctx;
// Increment overflow counter on overflow
if (edata->watch_point_value == EXAMPLE_PCNT_HIGH_LIMIT) {
overflow_count++;
}
// send event data to queue, from this interrupt callback
xQueueSendFromISR(queue, &(edata->watch_point_value), &high_task_wakeup);
return (high_task_wakeup == pdTRUE);
}
extern "C" void app_main(void)
{
ESP_LOGI(TAG, "install pcnt unit");
pcnt_unit_config_t unit_config = {
.low_limit = EXAMPLE_PCNT_LOW_LIMIT,
.high_limit = EXAMPLE_PCNT_HIGH_LIMIT,
};
pcnt_unit_handle_t pcnt_unit = NULL;
ESP_ERROR_CHECK(pcnt_new_unit(&unit_config, &pcnt_unit));
ESP_LOGI(TAG, "install pcnt channel");
pcnt_chan_config_t chan_config = {
.edge_gpio_num = EXAMPLE_EC11_GPIO_A,
.level_gpio_num = -1, // No level GPIO used
};
pcnt_channel_handle_t pcnt_chan = NULL;
ESP_ERROR_CHECK(pcnt_new_channel(pcnt_unit, &chan_config, &pcnt_chan));
ESP_LOGI(TAG, "set edge action for pcnt channel");
ESP_ERROR_CHECK(pcnt_channel_set_edge_action(pcnt_chan, PCNT_CHANNEL_EDGE_ACTION_INCREASE, PCNT_CHANNEL_EDGE_ACTION_HOLD));
ESP_LOGI(TAG, "add watch points and register callbacks");
int watch_points[] = {EXAMPLE_PCNT_LOW_LIMIT, -50, 0, 50, EXAMPLE_PCNT_HIGH_LIMIT};
for (size_t i = 0; i < sizeof(watch_points) / sizeof(watch_points[0]); i++) {
ESP_ERROR_CHECK(pcnt_unit_add_watch_point(pcnt_unit, watch_points[i]));
}
pcnt_event_callbacks_t cbs = {
.on_reach = example_pcnt_on_reach,
};
QueueHandle_t queue = xQueueCreate(10, sizeof(int));
ESP_ERROR_CHECK(pcnt_unit_register_event_callbacks(pcnt_unit, &cbs, queue));
ESP_LOGI(TAG, "enable pcnt unit");
ESP_ERROR_CHECK(pcnt_unit_enable(pcnt_unit));
ESP_LOGI(TAG, "clear pcnt unit");
ESP_ERROR_CHECK(pcnt_unit_clear_count(pcnt_unit));
ESP_LOGI(TAG, "start pcnt unit");
ESP_ERROR_CHECK(pcnt_unit_start(pcnt_unit));
// Configure GPIO interrupt on pin 10
ESP_LOGI(TAG, "configure GPIO interrupt on pin 10");
gpio_config_t io_conf;
io_conf.intr_type = GPIO_INTR_POSEDGE;
io_conf.mode = GPIO_MODE_INPUT;
io_conf.pin_bit_mask = (1ULL << EXAMPLE_GPIO_INTERRUPT_PIN);
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
ESP_ERROR_CHECK(gpio_config(&io_conf));
// Install ISR service
ESP_ERROR_CHECK(gpio_install_isr_service(0));
ESP_ERROR_CHECK(gpio_isr_handler_add(EXAMPLE_GPIO_INTERRUPT_PIN, gpio_isr_handler, (void *)pcnt_unit));
#if CONFIG_EXAMPLE_WAKE_UP_LIGHT_SLEEP
// EC11 channel output high level in normal state, so we set "low level" to wake up the chip
ESP_ERROR_CHECK(gpio_wakeup_enable(EXAMPLE_EC11_GPIO_A, GPIO_INTR_LOW_LEVEL));
ESP_ERROR_CHECK(esp_sleep_enable_gpio_wakeup());
ESP_ERROR_CHECK(esp_light_sleep_start());
#endif
// Report counter value
int pulse_count = 0;
int event_count = 0;
while (1) {
vTaskDelay(pdMS_TO_TICKS(100));
}
}