esp32[s2|s3]: Add pulse counter support

This commit is contained in:
Eren Terzioglu
2024-11-12 12:53:16 +01:00
committed by Alan C. Assis
parent e48d092778
commit 767c5f16f0
26 changed files with 3773 additions and 17 deletions
@@ -0,0 +1,79 @@
/****************************************************************************
* boards/xtensa/esp32/common/include/esp32_board_pcnt.h
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
#ifndef __BOARDS_XTENSA_ESP32_COMMON_INCLUDE_ESP32_BOARD_PCNT_H
#define __BOARDS_XTENSA_ESP32_COMMON_INCLUDE_ESP32_BOARD_PCNT_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Public Types
****************************************************************************/
/****************************************************************************
* Public Data
****************************************************************************/
#ifdef __cplusplus
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif
/****************************************************************************
* Inline Functions
****************************************************************************/
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
/****************************************************************************
* Name: board_pcnt_initialize
*
* Description:
* Initialize the pulse counter/quadrature encoder driver
*
* Input Parameters:
* None
*
* Returned Value:
* OK on success; errno on failure.
*
****************************************************************************/
int board_pcnt_initialize(void);
#undef EXTERN
#ifdef __cplusplus
}
#endif
#endif /* __BOARDS_XTENSA_ESP32_COMMON_INCLUDE_ESP32_BOARD_PCNT_H */
+2 -2
View File
@@ -38,8 +38,8 @@ ifeq ($(CONFIG_ESP32_I2S),y)
CSRCS += esp32_board_i2sdev.c
endif
ifeq ($(CONFIG_ESP32_PCNT_AS_QE),y)
CSRCS += esp32_qencoder.c
ifeq ($(CONFIG_ESP_PCNT),y)
CSRCS += esp32_board_pcnt.c
endif
ifeq ($(CONFIG_SENSORS_MAX6675),y)
@@ -0,0 +1,332 @@
/****************************************************************************
* boards/xtensa/esp32/common/src/esp32_board_pcnt.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <errno.h>
#include <debug.h>
#include <stdio.h>
#include <arch/board/board.h>
#include <nuttx/timers/capture.h>
#include <nuttx/sensors/sensor.h>
#include "espressif/esp_pcnt.h"
#ifdef CONFIG_ESP_PCNT_AS_QE
#include "espressif/esp_qencoder.h"
#endif
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define PCNT_HIGH_LIMIT 1000
#define PCNT_LOW_LIMIT -1000
#define PCNT_GLITCH_FILTER(pcnt, thres) pcnt->ops->ioctl(pcnt, \
CAPIOC_FILTER, \
thres) \
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: board_pcnt_init
*
* Description:
* Initialize and register the pulse counter driver
*
* Input Parameters:
* devpath - The full path to the driver to register.
* unit_cfg - PCNT unit configuration
* chan0_cfg - PCNT unit channel 0 configuration
* chan1_cfg - PCNT unit channel 1 configuration
* glitch_threshold - Threshold value for glitch filter in ns
*
* Returned Value:
* Valid PCNT device structure reference on success; NULL, otherwise.
*
****************************************************************************/
static struct cap_lowerhalf_s *board_pcnt_init(
const char *devpath,
struct esp_pcnt_unit_config_s *unit_cfg,
struct esp_pcnt_chan_config_s *chan0_cfg,
struct esp_pcnt_chan_config_s *chan1_cfg,
uint32_t glitch_threshold)
{
struct cap_lowerhalf_s *pcnt;
int chan0;
int chan1;
int ret;
pcnt = esp_pcnt_new_unit(unit_cfg);
if (!pcnt)
{
syslog(LOG_ERR, "Failed to create unit!\n");
return NULL;
}
chan0 = esp_pcnt_new_channel(pcnt, chan0_cfg);
if (chan0 == ERROR)
{
syslog(LOG_ERR, "Failed to create channel!\n");
esp_pcnt_del_unit(pcnt);
return NULL;
}
#ifdef CONFIG_ESP_PCNT_TEST_MODE
esp_pcnt_channel_set_edge_action(chan0, ESP_PCNT_CHAN_EDGE_ACTION_HOLD,
ESP_PCNT_CHAN_EDGE_ACTION_INCREASE);
esp_pcnt_channel_set_level_action(chan0, ESP_PCNT_CHAN_LEVEL_ACTION_KEEP,
ESP_PCNT_CHAN_LEVEL_ACTION_KEEP);
#else
esp_pcnt_channel_set_edge_action(chan0, ESP_PCNT_CHAN_EDGE_ACTION_DECREASE,
ESP_PCNT_CHAN_EDGE_ACTION_INCREASE);
esp_pcnt_channel_set_level_action(chan0, ESP_PCNT_CHAN_LEVEL_ACTION_KEEP,
ESP_PCNT_CHAN_LEVEL_ACTION_INVERSE);
#endif
if (chan1_cfg)
{
chan1 = esp_pcnt_new_channel(pcnt, chan1_cfg);
if (chan1 == ERROR)
{
syslog(LOG_ERR, "Failed to create channel!\n");
esp_pcnt_del_channel(chan0);
esp_pcnt_del_unit(pcnt);
return NULL;
}
esp_pcnt_channel_set_edge_action(chan1,
ESP_PCNT_CHAN_EDGE_ACTION_INCREASE,
ESP_PCNT_CHAN_EDGE_ACTION_DECREASE);
esp_pcnt_channel_set_level_action(chan1,
ESP_PCNT_CHAN_LEVEL_ACTION_KEEP,
ESP_PCNT_CHAN_LEVEL_ACTION_INVERSE);
}
PCNT_GLITCH_FILTER(pcnt, glitch_threshold);
ret = cap_register(devpath, pcnt);
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: Error registering PCNT!\n");
esp_pcnt_del_channel(chan0);
if (chan1_cfg)
{
esp_pcnt_del_channel(chan1);
}
esp_pcnt_del_unit(pcnt);
return NULL;
}
return pcnt;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: board_pcnt_initialize
*
* Description:
* Initialize the pulse counter/quadrature encoder driver
*
* Input Parameters:
* None
*
* Returned Value:
* OK on success; errno on failure.
*
****************************************************************************/
int board_pcnt_initialize(void)
{
struct cap_lowerhalf_s *pcnt;
int ret = OK;
int glitch_threshold = 0;
#ifdef CONFIG_ESP_PCNT_AS_QE
char devpath[12];
int devno = 0;
#endif
struct esp_pcnt_unit_config_s unit_cfg =
{
.high_limit = PCNT_HIGH_LIMIT,
.low_limit = PCNT_LOW_LIMIT,
.accum_count = false,
};
struct esp_pcnt_chan_config_s chan0_cfg =
{
0
};
struct esp_pcnt_chan_config_s chan1_cfg =
{
0
};
#ifdef CONFIG_ESP_PCNT_U0
chan0_cfg.edge_gpio_num = CONFIG_ESP_PCNT_U0_CH0_EDGE_PIN;
chan0_cfg.level_gpio_num = CONFIG_ESP_PCNT_U0_CH0_LEVEL_PIN;
#ifdef CONFIG_ESP_PCNT_TEST_MODE
chan0_cfg.flags = ESP_PCNT_CHAN_IO_LOOPBACK;
#endif
chan1_cfg.edge_gpio_num = CONFIG_ESP_PCNT_U0_CH1_LEVEL_PIN;
chan1_cfg.level_gpio_num = CONFIG_ESP_PCNT_U0_CH1_EDGE_PIN;
#ifndef CONFIG_ESP_PCNT_U0_FILTER_EN
glitch_threshold = 0;
#else
glitch_threshold = CONFIG_ESP_PCNT_U0_FILTER_THRES;
#endif
pcnt = board_pcnt_init("/dev/pcnt0", &unit_cfg, &chan0_cfg,
&chan1_cfg, glitch_threshold);
if (!pcnt)
{
syslog(LOG_ERR, "ERROR: pcnt initialize failed: %d\n", ret);
return ERROR;
}
#ifdef CONFIG_ESP_PCNT_U0_QE
snprintf(devpath, sizeof(devpath), "/dev/qe%d", devno++);
ret = esp_qeinitialize(devpath, pcnt, 0);
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: esp_qeinitialize failed: %d\n", ret);
return ret;
}
pcnt = NULL;
#endif
#endif
#ifdef CONFIG_ESP_PCNT_U1
chan0_cfg.edge_gpio_num = CONFIG_ESP_PCNT_U1_CH0_EDGE_PIN;
chan0_cfg.level_gpio_num = CONFIG_ESP_PCNT_U1_CH0_LEVEL_PIN;
chan1_cfg.edge_gpio_num = CONFIG_ESP_PCNT_U1_CH1_EDGE_PIN;
chan1_cfg.level_gpio_num = CONFIG_ESP_PCNT_U1_CH1_LEVEL_PIN;
#ifndef CONFIG_ESP_PCNT_U1_FILTER_EN
glitch_threshold = 0;
#else
glitch_threshold = CONFIG_ESP_PCNT_U1_FILTER_THRES;
#endif
pcnt = board_pcnt_init("/dev/pcnt1", &unit_cfg, &chan0_cfg,
&chan1_cfg, glitch_threshold);
if (!pcnt)
{
syslog(LOG_ERR, "ERROR: pcnt initialize failed: %d\n", ret);
return ERROR;
}
#ifdef CONFIG_ESP_PCNT_U1_QE
snprintf(devpath, sizeof(devpath), "/dev/qe%d", devno++);
ret = esp_qeinitialize(devpath, pcnt, 1);
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: esp_qeinitialize failed: %d\n", ret);
return ret;
}
pcnt = NULL;
#endif
#endif
#ifdef CONFIG_ESP_PCNT_U2
chan0_cfg.edge_gpio_num = CONFIG_ESP_PCNT_U2_CH0_EDGE_PIN;
chan0_cfg.level_gpio_num = CONFIG_ESP_PCNT_U2_CH0_LEVEL_PIN;
chan1_cfg.edge_gpio_num = CONFIG_ESP_PCNT_U2_CH1_EDGE_PIN;
chan1_cfg.level_gpio_num = CONFIG_ESP_PCNT_U2_CH1_LEVEL_PIN;
#ifndef CONFIG_ESP_PCNT_U2_FILTER_EN
glitch_threshold = 0;
#else
glitch_threshold = CONFIG_ESP_PCNT_U2_FILTER_THRES;
#endif
pcnt = board_pcnt_init("/dev/pcnt2", &unit_cfg, &chan0_cfg,
&chan1_cfg, glitch_threshold);
if (!pcnt)
{
syslog(LOG_ERR, "ERROR: pcnt initialize failed: %d\n", ret);
return ERROR;
}
#ifdef CONFIG_ESP_PCNT_U2_QE
snprintf(devpath, sizeof(devpath), "/dev/qe%d", devno++);
ret = esp_qeinitialize(devpath, pcnt, 2);
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: esp_qeinitialize failed: %d\n", ret);
return ret;
}
pcnt = NULL;
#endif
#endif
#ifdef CONFIG_ESP_PCNT_U3
chan0_cfg.edge_gpio_num = CONFIG_ESP_PCNT_U3_CH0_EDGE_PIN;
chan0_cfg.level_gpio_num = CONFIG_ESP_PCNT_U3_CH0_LEVEL_PIN;
chan1_cfg.edge_gpio_num = CONFIG_ESP_PCNT_U3_CH1_EDGE_PIN;
chan1_cfg.level_gpio_num = CONFIG_ESP_PCNT_U3_CH1_LEVEL_PIN;
#ifndef CONFIG_ESP_PCNT_U3_FILTER_EN
glitch_threshold = 0;
#else
glitch_threshold = CONFIG_ESP_PCNT_U3_FILTER_THRES;
#endif
pcnt = board_pcnt_init("/dev/pcnt3", &unit_cfg, &chan0_cfg,
&chan1_cfg, glitch_threshold);
if (!pcnt)
{
syslog(LOG_ERR, "ERROR: pcnt initialize failed: %d\n", ret);
return ERROR;
}
#ifdef CONFIG_ESP_PCNT_U3_QE
snprintf(devpath, sizeof(devpath), "/dev/qe%d", devno++);
ret = esp_qeinitialize(devpath, pcnt, 3);
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: esp_qeinitialize failed: %d\n", ret);
return ret;
}
pcnt = NULL;
#endif
#endif
return ret;
}
@@ -70,6 +70,11 @@
# include "board_qencoder.h"
#endif
#ifdef CONFIG_ESP_PCNT
# include "espressif/esp_pcnt.h"
# include "esp32_board_pcnt.h"
#endif
#ifdef CONFIG_ESP32_RT_TIMER
# include "esp32_rt_timer.h"
#endif
@@ -357,6 +362,14 @@ int esp32_bringup(void)
}
#endif
#ifdef CONFIG_ESP_PCNT
ret = board_pcnt_initialize();
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: board_pcnt_initialize failed: %d\n", ret);
}
#endif
#ifdef CONFIG_RTC_DRIVER
/* Instantiate the ESP32 RTC driver */
@@ -94,8 +94,9 @@
# include "esp32_i2s.h"
#endif
#ifdef CONFIG_ESP32_PCNT_AS_QE
# include "board_qencoder.h"
#ifdef CONFIG_ESP_PCNT
# include "espressif/esp_pcnt.h"
# include "esp32_board_pcnt.h"
#endif
#ifdef CONFIG_I2CMULTIPLEXER_TCA9548A
@@ -475,16 +476,11 @@ int esp32_bringup(void)
}
#endif
#ifdef CONFIG_SENSORS_QENCODER
/* Initialize and register the qencoder driver */
ret = board_qencoder_initialize(0, PCNT_QE0_ID);
if (ret != OK)
#ifdef CONFIG_ESP_PCNT
ret = board_pcnt_initialize();
if (ret < 0)
{
syslog(LOG_ERR,
"ERROR: Failed to register the qencoder: %d\n",
ret);
return ret;
syslog(LOG_ERR, "ERROR: board_pcnt_initialize failed: %d\n", ret);
}
#endif