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

View file

@ -340,7 +340,7 @@ I2C Yes
I2S Yes I2S Yes
LED_PWM Yes LED_PWM Yes
MCPWM Yes MCPWM Yes
Pulse_CNT No Pulse_CNT Yes
RMT Yes RMT Yes
RNG Yes RNG Yes
RSA No RSA No

View file

@ -326,7 +326,7 @@ GPIO Yes
I2C Yes I2C Yes
I2S Yes I2S Yes
LED_PWM No LED_PWM No
Pulse_CNT No Pulse_CNT Yes
RMT No RMT No
RNG Yes RNG Yes
RSA No RSA No

View file

@ -363,7 +363,7 @@ I2S Yes
LCD No LCD No
LED_PWM No LED_PWM No
MCPWM Yes MCPWM Yes
Pulse_CNT No Pulse_CNT Yes
RMT No RMT No
RNG No RNG No
RSA No RSA No

View file

@ -16,6 +16,11 @@ config ESP_MCPWM
Enable support for timer capture and motor control using Enable support for timer capture and motor control using
the Motor Control PWM peripheral. the Motor Control PWM peripheral.
config ESP_PCNT
bool "Pulse Counter (PCNT / QE) Module"
default n
select CAPTURE
config ESPRESSIF_TEMP config ESPRESSIF_TEMP
bool "Internal Temperature Sensor" bool "Internal Temperature Sensor"
default n default n
@ -61,6 +66,226 @@ config ESPRESSIF_SPIFLASH
depends on ARCH_CHIP_ESP32S2 depends on ARCH_CHIP_ESP32S2
default n default n
menu "Pulse Counter (PCNT) Configuration"
depends on ESP_PCNT
config ESP_PCNT_TEST_MODE
bool "Pulse Counter character driver loopback test mode (for testing only)"
default n
---help---
This enables a loopback test mode that attaches the transmitter
to the receiver internally, being able to test the PCNT
peripheral without any external connection.
config ESP_PCNT_AS_QE
bool
default n
config ESP_PCNT_U0
bool "Enable PCNT Unit 0"
default n
if ESP_PCNT_U0
config ESP_PCNT_U0_QE
bool "Use this PCNT Unit as Quadrature Encoder"
default n
select ESP_PCNT_AS_QE
config ESP_PCNT_U0_CH0_EDGE_PIN
int "PCNT_U0 CH0 Edge/Pulse Pin Number"
default 0
range -1 39
config ESP_PCNT_U0_CH0_LEVEL_PIN
int "PCNT_U0 CH0 Level/Control Pin Number"
default 4 if !ESP_PCNT_U0_QE
default -1 if ESP_PCNT_U0_QE
range -1 39
config ESP_PCNT_U0_CH1_EDGE_PIN
int "PCNT_U0 CH1 Edge/Pulse Pin Number"
default 0 if !ESP_PCNT_U0_QE
default -1 if ESP_PCNT_U0_QE
range -1 39
config ESP_PCNT_U0_CH1_LEVEL_PIN
int "PCNT_U0 CH1 Level/Control Pin Number"
default 4
range -1 39
config ESP_PCNT_U0_FILTER_EN
bool "Enable Glitch Filter for this PCNT Unit"
default n
if ESP_PCNT_U0_FILTER_EN
config ESP_PCNT_U0_FILTER_THRES
int "PCNT_U0 Filter Threshold value"
default 5
---help---
If a pulse is shorter than this number of APB_CLK clock cycles
then it will not be considered as a valid pulse.
endif # ESP_PCNT_U0_FILTER_EN
endif # ESP_PCNT_U0
config ESP_PCNT_U1
bool "Enable PCNT Unit 1"
depends on ESP_PCNT_U0
default n
if ESP_PCNT_U1
config ESP_PCNT_U1_QE
bool "Use this PCNT Unit as Quadrature Encoder"
default n
select ESP_PCNT_AS_QE
config ESP_PCNT_U1_CH0_EDGE_PIN
int "PCNT_U1 CH0 Edge/Pulse Pin Number"
default 0
range -1 39
config ESP_PCNT_U1_CH0_LEVEL_PIN
int "PCNT_U1 CH0 Level/Control Pin Number"
default 4
range -1 39
depends on !ESP_PCNT_U1_QE
config ESP_PCNT_U1_CH1_EDGE_PIN
int "PCNT_U1 CH1 Edge/Pulse Pin Number"
default 0
range -1 39
depends on !ESP_PCNT_U1_QE
config ESP_PCNT_U1_CH1_LEVEL_PIN
int "PCNT_U1 CH1 Level/Control Pin Number"
default 4
range -1 39
config ESP_PCNT_U1_FILTER_EN
bool "Enable Glitch Filter for this PCNT Unit"
default n
if ESP_PCNT_U1_FILTER_EN
config ESP_PCNT_U1_FILTER_THRES
int "PCNT_U1 Filter Threshold value"
default 5
---help---
If a pulse is shorter than this number of APB_CLK clock cycles
then it will not be considered as a valid pulse.
endif # ESP_PCNT_U1_FILTER_EN
endif # ESP_PCNT_U1
config ESP_PCNT_U2
bool "Enable PCNT Unit 2"
depends on ESP_PCNT_U1
default n
if ESP_PCNT_U2
config ESP_PCNT_U2_QE
bool "Use this PCNT Unit as Quadrature Encoder"
default n
select ESP_PCNT_AS_QE
config ESP_PCNT_U2_CH0_EDGE_PIN
int "PCNT_U2 CH0 Edge/Pulse Pin Number"
default 0
range -1 39
config ESP_PCNT_U2_CH0_LEVEL_PIN
int "PCNT_U2 CH0 Level/Control Pin Number"
default 4
range -1 39
depends on !ESP_PCNT_U2_QE
config ESP_PCNT_U2_CH1_EDGE_PIN
int "PCNT_U2 CH1 Edge/Pulse Pin Number"
default 0
range -1 39
depends on !ESP_PCNT_U2_QE
config ESP_PCNT_U2_CH1_LEVEL_PIN
int "PCNT_U2 CH1 Level/Control Pin Number"
default 4
range -1 39
config ESP_PCNT_U2_FILTER_EN
bool "Enable Glitch Filter for this PCNT Unit"
default n
if ESP_PCNT_U2_FILTER_EN
config ESP_PCNT_U2_FILTER_THRES
int "PCNT_U2 Filter Threshold value"
default 5
---help---
If a pulse is shorter than this number of APB_CLK clock cycles
then it will not be considered as a valid pulse.
endif # ESP_PCNT_U2_FILTER_EN
endif # ESP_PCNT_U2
config ESP_PCNT_U3
bool "Enable PCNT Unit 3"
depends on ESP_PCNT_U2
default n
if ESP_PCNT_U3
config ESP_PCNT_U3_QE
bool "Use this PCNT Unit as Quadrature Encoder"
default n
select ESP_PCNT_AS_QE
config ESP_PCNT_U3_CH0_EDGE_PIN
int "PCNT_U3 CH0 Edge/Pulse Pin Number"
default 0
range -1 39
config ESP_PCNT_U3_CH0_LEVEL_PIN
int "PCNT_U3 CH0 Level/Control Pin Number"
default 4
range -1 39
depends on !ESP_PCNT_U3_QE
config ESP_PCNT_U3_CH1_EDGE_PIN
int "PCNT_U3 CH1 Edge/Pulse Pin Number"
default 0
range -1 39
depends on !ESP_PCNT_U3_QE
config ESP_PCNT_U3_CH1_LEVEL_PIN
int "PCNT_U3 CH1 Level/Control Pin Number"
default 4
range -1 39
config ESP_PCNT_U3_FILTER_EN
bool "Enable Glitch Filter for this PCNT Unit"
default n
if ESP_PCNT_U3_FILTER_EN
config ESP_PCNT_U3_FILTER_THRES
int "PCNT_U3 Filter Threshold value"
default 5
---help---
If a pulse is shorter than this number of APB_CLK clock cycles
then it will not be considered as a valid pulse.
endif # ESP_PCNT_U3_FILTER_EN
endif # ESP_PCNT_U3
endmenu # ESP_PCNT
menu "Internal Temperature Sensor Configuration" menu "Internal Temperature Sensor Configuration"
depends on ESPRESSIF_TEMP depends on ESPRESSIF_TEMP

View file

@ -50,6 +50,13 @@ ifeq ($(CONFIG_ESPRESSIF_SPI_BITBANG),y)
CHIP_CSRCS += esp_spi_bitbang.c CHIP_CSRCS += esp_spi_bitbang.c
endif endif
ifeq ($(CONFIG_ESP_PCNT),y)
CHIP_CSRCS += esp_pcnt.c
ifeq ($(CONFIG_ESP_PCNT_AS_QE),y)
CHIP_CSRCS += esp_qencoder.c
endif
endif
ifeq ($(CONFIG_ESPRESSIF_SPIFLASH),y) ifeq ($(CONFIG_ESPRESSIF_SPIFLASH),y)
CHIP_CSRCS += esp_spiflash.c CHIP_CSRCS += esp_spiflash.c
ifeq ($(CONFIG_ESPRESSIF_MTD),y) ifeq ($(CONFIG_ESPRESSIF_MTD),y)

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,236 @@
/****************************************************************************
* arch/xtensa/src/common/espressif/esp_pcnt.h
*
* SPDX-License-Identifier: Apache-2.0
*
* 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 __ARCH_XTENSA_SRC_COMMON_ESPRESSIF_ESP_PCNT_H
#define __ARCH_XTENSA_SRC_COMMON_ESPRESSIF_ESP_PCNT_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define ESP_PCNT_CHAN_INVERT_EDGE_IN (1 << 0)
#define ESP_PCNT_CHAN_INVERT_LVL_IN (1 << 1)
#define ESP_PCNT_CHAN_VIRT_EDGE_IO_LVL (1 << 2)
#define ESP_PCNT_CHAN_VIRT_LVL_IO_LVL (1 << 3)
#define ESP_PCNT_CHAN_IO_LOOPBACK (1 << 4)
/****************************************************************************
* Public Types
****************************************************************************/
enum esp_pcnt_chan_level_action_e
{
ESP_PCNT_CHAN_LEVEL_ACTION_KEEP, /* Keep current count mode */
ESP_PCNT_CHAN_LEVEL_ACTION_INVERSE, /* Invert current count mode */
ESP_PCNT_CHAN_LEVEL_ACTION_HOLD, /* Hold current count value */
};
enum esp_pcnt_chan_edge_action_e
{
ESP_PCNT_CHAN_EDGE_ACTION_HOLD, /* Hold current count value */
ESP_PCNT_CHAN_EDGE_ACTION_INCREASE, /* Increase count value */
ESP_PCNT_CHAN_EDGE_ACTION_DECREASE, /* Decrease count value */
};
enum esp_pcnt_unit_zero_cross_mode_e
{
ESP_PCNT_UNIT_ZERO_CROSS_POS_ZERO, /* From positive value to zero */
ESP_PCNT_UNIT_ZERO_CROSS_NEG_ZERO, /* From negative value, to zero */
ESP_PCNT_UNIT_ZERO_CROSS_NEG_POS, /* From negative value, to positive value */
ESP_PCNT_UNIT_ZERO_CROSS_POS_NEG, /* From positive value, to negative value */
};
struct esp_pcnt_unit_config_s
{
int low_limit; /* Low limitation of the count unit */
int high_limit; /* High limitation of the count unit */
bool accum_count; /* Accumulate the count value when overflow flag */
};
struct esp_pcnt_chan_config_s
{
int edge_gpio_num; /* Edge signal GPIO number,-1 if unused */
int level_gpio_num; /* Level signal GPIO number ,-1 if unused */
int flags; /* Channel config flags */
};
struct esp_pcnt_watch_event_data_s
{
int unit_id; /* PCNT Unit id */
int watch_point_value; /* Watch point value that triggered the event */
enum esp_pcnt_unit_zero_cross_mode_e zero_cross_mode; /* Zero cross mode */
};
/****************************************************************************
* Public functions
****************************************************************************/
/****************************************************************************
* Name: esp_pcnt_new_unit
*
* Description:
* Request PCNT unit and config it with given parameters.
*
* Input Parameters:
* config - PCNT unit configuration
*
* Returned Value:
* PCNT unit number (>=0) if success or -1 if fail.
*
****************************************************************************/
struct cap_lowerhalf_s *esp_pcnt_new_unit(
struct esp_pcnt_unit_config_s *config);
/****************************************************************************
* Name: esp_pcnt_del_unit
*
* Description:
* Delete PCNT unit.
*
* Input Parameters:
* dev - Pointer to the pcnt driver struct
*
* Returned Value:
* OK on success; ERROR on failure
*
****************************************************************************/
int esp_pcnt_del_unit(struct cap_lowerhalf_s *dev);
/****************************************************************************
* Name: esp_pcnt_unit_add_watch_point
*
* Description:
* Add watch point to given PCNT unit.
*
* Input Parameters:
* dev - Pointer to the pcnt driver struct
* ret - Value to watch
*
* Returned Value:
* OK on success; ERROR on failure
*
****************************************************************************/
int esp_pcnt_unit_add_watch_point(struct cap_lowerhalf_s *dev,
int watch_point);
/****************************************************************************
* Name: esp_pcnt_unit_remove_watch_point
*
* Description:
* Remove watch point from given PCNT unit.
*
* Input Parameters:
* dev - Pointer to the pcnt driver struct
* ret - Watch point value to remove
*
* Returned Value:
* OK on success; ERROR on failure
*
****************************************************************************/
int esp_pcnt_unit_remove_watch_point(struct cap_lowerhalf_s *dev,
int watch_point);
/****************************************************************************
* Name: esp_pcnt_new_channel
*
* Description:
* Request channel on given PCNT unit and config it with given parameters.
*
* Input Parameters:
* dev - Pointer to the pcnt driver struct
* config - PCNT unit channel configuration
*
* Returned Value:
* PCNT unit channel number (>=0) if success or -1 if fail.
*
****************************************************************************/
int esp_pcnt_new_channel(struct cap_lowerhalf_s *dev,
struct esp_pcnt_chan_config_s *config);
/****************************************************************************
* Name: esp_pcnt_del_channel
*
* Description:
* Delete PCNT unit channel.
*
* Input Parameters:
* channel - Channel number to delete
*
* Returned Value:
* OK on success; ERROR on failure
*
****************************************************************************/
int esp_pcnt_del_channel(int channel);
/****************************************************************************
* Name: esp_pcnt_channel_set_edge_action
*
* Description:
* Set channel actions when edge signal changes.
*
* Input Parameters:
* channel - Channel number to set actions
* post act - Action on posedge signal
* neg_act - Action on negedge signal
*
* Returned Value:
* OK on success; ERROR on failure
*
****************************************************************************/
void esp_pcnt_channel_set_edge_action(int channel,
enum esp_pcnt_chan_edge_action_e pos_act,
enum esp_pcnt_chan_edge_action_e neg_act);
/****************************************************************************
* Name: esp_pcnt_channel_set_level_action
*
* Description:
* Set channel actions when level signal changes.
*
* Input Parameters:
* channel - Channel number to set actions
* post act - Action on posedge signal
* neg_act - Action on negedge signal
*
* Returned Value:
* OK on success; ERROR on failure
*
****************************************************************************/
void esp_pcnt_channel_set_level_action(int channel,
enum esp_pcnt_chan_level_action_e pos_act,
enum esp_pcnt_chan_level_action_e neg_act);
#endif /* __ARCH_XTENSA_SRC_COMMON_ESPRESSIF_ESP_PCNT_H */

View file

@ -0,0 +1,499 @@
/****************************************************************************
* arch/xtensa/src/common/espressif/esp_qencoder.c
*
* SPDX-License-Identifier: Apache-2.0
*
* 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 <stdint.h>
#include <assert.h>
#include <errno.h>
#include <debug.h>
#include <inttypes.h>
#include <nuttx/arch.h>
#include <nuttx/irq.h>
#include <nuttx/spinlock.h>
#include <nuttx/sensors/qencoder.h>
#include <nuttx/sensors/sensor.h>
#include <nuttx/timers/capture.h>
#include <arch/board/board.h>
#ifdef CONFIG_SENSORS_QENCODER
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Input filter *************************************************************/
#ifdef CONFIG_ESP_PCNT_U0_QE
# ifndef CONFIG_ESP_PCNT_U0_FILTER_EN
# warning "Glitch Filter is recommended for Quadrature Encoder on PCNT_U0"
# endif
#endif
#ifdef CONFIG_ESP_PCNT_U1_QE
# ifndef CONFIG_ESP_PCNT_U1_FILTER_EN
# warning "Glitch Filter is recommended for Quadrature Encoder on PCNT_U1"
# endif
#endif
#ifdef CONFIG_ESP_PCNT_U2_QE
# ifndef CONFIG_ESP_PCNT_U2_FILTER_EN
# warning "Glitch Filter is recommended for Quadrature Encoder on PCNT_U2"
# endif
#endif
#ifdef CONFIG_ESP_PCNT_U3_QE
# ifndef CONFIG_ESP_PCNT_U3_FILTER_EN
# warning "Glitch Filter is recommended for Quadrature Encoder on PCNT_U3"
# endif
#endif
/****************************************************************************
* Private Types
****************************************************************************/
/* NOTE: we are using Quadrature Encoder in X4 mode on ESP PCNT, then
* instead of using 'pulse_gpio' and 'ctrl_gpio' names, we only use ch0_gpio
* and ch1_gpio names. It avoids confusion, since the same signal that is
* used on pin 'pulse' of CH0 is also connected to 'ctrl' pin of the CH1 and
* 'ctrl' pin of CH0 is also connected on 'pulse' pin of CH1.
*/
/* Overall, RAM-based state structure */
struct qe_dev_lowerhalf_s
{
/* The first field of this state structure must be a pointer to the
* lower-half callback structure:
*/
const struct qe_ops_s *ops; /* Lower half callback structure */
/* ESP driver-specific fields: */
struct cap_lowerhalf_s *pcnt; /* Device handle */
int pcnt_num; /* Pulse Counter (PCNT) unit number */
bool inuse; /* True: The lower-half driver is in-use */
volatile int32_t position; /* The current position offset */
spinlock_t lock; /* Device specific lock. */
};
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/* Lower-half Quadrature Encoder Driver Methods */
static int esp_setup(struct qe_lowerhalf_s *lower);
static int esp_shutdown(struct qe_lowerhalf_s *lower);
static int esp_position(struct qe_lowerhalf_s *lower,
int32_t *pos);
static int esp_setposmax(struct qe_lowerhalf_s *lower, uint32_t pos);
static int esp_reset(struct qe_lowerhalf_s *lower);
static int esp_setindex(struct qe_lowerhalf_s *lower, uint32_t pos);
static int esp_ioctl(struct qe_lowerhalf_s *lower, int cmd,
unsigned long arg);
/****************************************************************************
* Private Data
****************************************************************************/
/* The lower half callback structure */
static const struct qe_ops_s g_qecallbacks =
{
.setup = esp_setup,
.shutdown = esp_shutdown,
.position = esp_position,
.setposmax = esp_setposmax,
.reset = esp_reset,
.setindex = esp_setindex,
.ioctl = esp_ioctl,
};
/* Per-pcnt state structures */
#ifdef CONFIG_ESP_PCNT_U0_QE
static struct qe_dev_lowerhalf_s g_pcnt0lower =
{
.ops = &g_qecallbacks,
.inuse = false,
};
#endif
#ifdef CONFIG_ESP_PCNT_U1_QE
static struct qe_dev_lowerhalf_s g_pcnt1lower =
{
.ops = &g_qecallbacks,
.inuse = false,
};
#endif
#ifdef CONFIG_ESP_PCNT_U2_QE
static struct qe_dev_lowerhalf_s g_pcnt2lower =
{
.ops = &g_qecallbacks,
.inuse = false,
};
#endif
#ifdef CONFIG_ESP_PCNT_U3_QE
static struct qe_dev_lowerhalf_s g_pcnt3lower =
{
.ops = &g_qecallbacks,
.inuse = false,
};
#endif
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: esp_setup
*
* Description:
* This method is called when the driver is opened. The lower half driver
* should configure and initialize the device so that it is ready for use.
* The initial position value should be zero. *
*
* Input Parameters:
* lower - Pointer to Lower half driver structure
*
* Returned Value:
* Zero on success; A negated errno value is returned on failure.
*
****************************************************************************/
static int esp_setup(struct qe_lowerhalf_s *lower)
{
DEBUGASSERT(lower);
struct qe_dev_lowerhalf_s *priv = (struct qe_dev_lowerhalf_s *)lower;
irqstate_t flags;
/* Protected access to the registers */
flags = spin_lock_irqsave(&priv->lock);
/* Make sure that it is available */
if (priv->inuse)
{
snerr("ERROR: PCNT%d is in-use\n", priv->pcnt_num);
spin_unlock_irqrestore(&priv->lock, flags);
return -EBUSY;
}
/* Clear the Reset bit to enable the Pulse Counter */
priv->pcnt->ops->ioctl(priv->pcnt, CAPIOC_CLR_CNT, 0);
priv->pcnt->ops->start(priv->pcnt);
/* Mark as being used to prevent double opening of the same unit which
* would reset position
*/
priv->inuse = true;
spin_unlock_irqrestore(&priv->lock, flags);
return OK;
}
/****************************************************************************
* Name: esp_shutdown
*
* Description:
* This method is called when the driver is closed. The lower half driver
* should stop data collection, free any resources, disable timer hardware,
* and put the system into the lowest possible power usage state
*
* Input Parameters:
* lower - Pointer to Lower half driver structure
*
* Returned Value:
* Zero on success; A negated errno value is returned on failure.
*
****************************************************************************/
static int esp_shutdown(struct qe_lowerhalf_s *lower)
{
DEBUGASSERT(lower);
struct qe_dev_lowerhalf_s *priv = (struct qe_dev_lowerhalf_s *)lower;
irqstate_t flags;
/* Protected access to the registers */
flags = spin_lock_irqsave(&priv->lock);
/* Disable interrupts */
priv->pcnt->ops->ioctl(priv->pcnt, SNIOC_DISABLE, 0);
/* Make sure initial position is 0 */
priv->position = 0;
priv->inuse = false;
spin_unlock_irqrestore(&priv->lock, flags);
return OK;
}
/****************************************************************************
* Name: esp_position
*
* Description:
* Return the current position measurement.
*
* Input Parameters:
* lower - Pointer to Lower half driver structure
* pos - Pointer to updated position measurement
*
* Returned Value:
* Zero on success; A negated errno value is returned on failure.
*
****************************************************************************/
static int esp_position(struct qe_lowerhalf_s *lower, int32_t *pos)
{
DEBUGASSERT(lower && pos);
struct qe_dev_lowerhalf_s *priv = (struct qe_dev_lowerhalf_s *)lower;
irqstate_t flags;
int32_t position;
int count = 0;
int ret = OK;
flags = spin_lock_irqsave(&priv->lock);
position = priv->position;
ret = (priv->pcnt->ops->ioctl(priv->pcnt,
CAPIOC_PULSES,
(unsigned long)&count) & 0xffff);
if (ret < 0)
{
snerr("ERROR: Failed to get PCNT%d count value \n", priv->pcnt_num);
}
/* Update the position measurement */
*pos = position + count;
spin_unlock_irqrestore(&priv->lock, flags);
return OK;
}
/****************************************************************************
* Name: esp_setposmax
*
* Description:
* Set the maximum encoder position.
*
* Input Parameters:
* lower - Pointer to Lower half driver structure
* pos - Requested maximum position
*
* Returned Value:
* Zero on success; A negated errno value is returned on failure.
*
****************************************************************************/
static int esp_setposmax(struct qe_lowerhalf_s *lower, uint32_t pos)
{
return -ENOTTY;
}
/****************************************************************************
* Name: esp_reset
*
* Description:
* Reset the position measurement to zero.
*
* Input Parameters:
* lower - Pointer to Lower half driver structure
*
* Returned Value:
* Zero on success; A negated errno value is returned on failure.
*
****************************************************************************/
static int esp_reset(struct qe_lowerhalf_s *lower)
{
DEBUGASSERT(lower);
struct qe_dev_lowerhalf_s *priv = (struct qe_dev_lowerhalf_s *)lower;
irqstate_t flags;
sninfo("Resetting position to zero\n");
/* Reset this Pulse Counter Unit. */
flags = spin_lock_irqsave(&priv->lock);
/* Reset RST bit and clear RST bit to enable counting again */
priv->pcnt->ops->ioctl(priv->pcnt, CAPIOC_CLR_CNT, 0);
priv->position = 0;
spin_unlock_irqrestore(&priv->lock, flags);
return OK;
}
/****************************************************************************
* Name: esp_setindex
*
* Description:
* Set the index pin position
*
* Input Parameters:
* lower - Pointer to Lower half driver structure
* pos - Requested index position
*
* Returned Value:
* Zero on success; A negated errno value is returned on failure.
*
****************************************************************************/
static int esp_setindex(struct qe_lowerhalf_s *lower, uint32_t pos)
{
return -ENOTTY;
}
/****************************************************************************
* Name: esp_ioctl
*
* Description:
* Lower-half logic may support platform-specific ioctl commands
*
* Input Parameters:
* lower - Pointer to Lower half driver structure
* cmd - Ioctl command
* arg - command argument
*
* Returned Value:
* Zero on success; A negated errno value is returned on failure.
*
****************************************************************************/
static int esp_ioctl(struct qe_lowerhalf_s *lower, int cmd,
unsigned long arg)
{
/* No ioctl commands supported */
/* TODO add an IOCTL to control the encoder pulse count prescaler */
return -ENOTTY;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: esp_qeinitialize
*
* Description:
* Initialize a quadrature encoder interface. This function must be
* called from board-specific logic.
*
* Input Parameters:
* devpath - The full path to the driver to register. E.g., "/dev/qe0"
* pcnt - Pointer to the pcnt driver struct
* pcnt_num - The PCNT number to used. 'pcnt' must be an element of
* {0,1,2,3}
*
* Returned Value:
* Zero on success; A negated errno value is returned on failure.
*
****************************************************************************/
int esp_qeinitialize(const char *devpath, struct cap_lowerhalf_s *pcnt,
int pcnt_num)
{
struct qe_dev_lowerhalf_s *priv;
int ret;
/* Find the pre-allocated timer state structure corresponding to this
* timer
*/
switch (pcnt_num)
{
#ifdef CONFIG_ESP_PCNT_U0_QE
case 0:
priv = &g_pcnt0lower;
break;
#endif
#ifdef CONFIG_ESP_PCNT_U1_QE
case 1:
priv = &g_pcnt1lower;
break;
#endif
#ifdef CONFIG_ESP_PCNT_U2_QE
case 2:
priv = &g_pcnt2lower;
break;
#endif
#ifdef CONFIG_ESP_PCNT_U3_QE
case 3:
priv = &g_pcnt3lower;
break;
#endif
default:
priv = NULL;
}
if (priv == NULL)
{
snerr("ERROR: PCNT%d support not configured\n", pcnt_num);
return -ENXIO;
}
/* Register the upper-half driver */
priv->pcnt = pcnt;
ret = qe_register(devpath, (struct qe_lowerhalf_s *)priv);
if (ret < 0)
{
snerr("ERROR: qe_register failed: %d\n", ret);
return ret;
}
priv->pcnt_num = pcnt_num;
return OK;
}
#endif /* CONFIG_SENSORS_QENCODER */

View file

@ -0,0 +1,83 @@
/****************************************************************************
* arch/xtensa/src/common/espressif/esp_qencoder.h
*
* SPDX-License-Identifier: Apache-2.0
*
* 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 __ARCH_XTENSA_SRC_COMMON_ESPRESSIF_ESP_QENCODER_H
#define __ARCH_XTENSA_SRC_COMMON_ESPRESSIF_ESP_QENCODER_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#ifdef CONFIG_SENSORS_QENCODER
/****************************************************************************
* Included Files
****************************************************************************/
/* Timer devices may be used for different purposes. One special purpose is
* as a quadrature encoder input device. If CONFIG_ESP_PCNT_Un is defined
* then the CONFIG_ESP_PCNT_Un_QE must also be defined to indicate that
* pcnt "n" is intended to be used for as a quadrature encoder.
*/
#ifndef CONFIG_ESP_PCNT_U0
# undef CONFIG_ESP_PCNT_U0_QE
#endif
#ifndef CONFIG_ESP_PCNT_U1
# undef CONFIG_ESP_PCNT_U1_QE
#endif
#ifndef CONFIG_ESP_PCNT_U2
# undef CONFIG_ESP_PCNT_U2_QE
#endif
#ifndef CONFIG_ESP_PCNT_U3
# undef CONFIG_ESP_PCNT_U3_QE
#endif
/****************************************************************************
* Included Files
****************************************************************************/
/****************************************************************************
* Name: esp_qeinitialize
*
* Description:
* Initialize a quadrature encoder interface. This function must be
* called from board-specific logic.
*
* Input Parameters:
* devpath - The full path to the driver to register. E.g., "/dev/qe0"
* pcnt - Pointer to the pcnt driver struct
* pcnt_num - The PCNT number to used. 'pcnt' must be an element of
* {0,1,2,3}
*
* Returned Value:
* Zero on success; A negated errno value is returned on failure.
*
****************************************************************************/
int esp_qeinitialize(const char *devpath, struct cap_lowerhalf_s *pcnt,
int pcnt_num);
#endif /* CONFIG_SENSORS_QENCODER */
#endif /* __ARCH_XTENSA_SRC_COMMON_ESPRESSIF_ESP_QENCODER_H */

View file

@ -290,9 +290,11 @@ config ESP32_LEDC
Enable support to PWM on ESP32 using LEDC peripheral. Enable support to PWM on ESP32 using LEDC peripheral.
config ESP32_PCNT config ESP32_PCNT
bool "Pulse Counter (PCNT / QE) Module" bool "Pulse Counter (PCNT / QE) Module (Legacy Driver)"
default n default n
depends on !ESP_PCNT
---help--- ---help---
Warning: this is deprecated option. Please use ESP_PCNT option
Pulse Counter is currently used to implement Quadracture Pulse Counter is currently used to implement Quadracture
Encoder. Encoder.

View file

@ -108,6 +108,7 @@ CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$
CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)gpio_hal.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)gpio_hal.c
CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)ledc_hal_iram.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)ledc_hal_iram.c
CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)ledc_hal.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)ledc_hal.c
CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)pcnt_hal.c
CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)rmt_hal.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)rmt_hal.c
CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)mcpwm_hal.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)mcpwm_hal.c
CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)timer_hal.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)timer_hal.c
@ -118,6 +119,7 @@ CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)log$
CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)log$(DELIM)log.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)log$(DELIM)log.c
CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)gpio_periph.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)gpio_periph.c
CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)ledc_periph.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)ledc_periph.c
CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)pcnt_periph.c
CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)rmt_periph.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)rmt_periph.c
CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)mcpwm_periph.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)mcpwm_periph.c

View file

@ -105,6 +105,7 @@ CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$
CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)gpio_hal.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)gpio_hal.c
CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)ledc_hal_iram.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)ledc_hal_iram.c
CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)ledc_hal.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)ledc_hal.c
CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)pcnt_hal.c
CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)rmt_hal.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)rmt_hal.c
CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)timer_hal.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)timer_hal.c
CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)uart_hal_iram.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)uart_hal_iram.c
@ -113,6 +114,7 @@ CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)log$
CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)log$(DELIM)log.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)log$(DELIM)log.c
CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)gpio_periph.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)gpio_periph.c
CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)ledc_periph.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)ledc_periph.c
CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)pcnt_periph.c
CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)rmt_periph.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)rmt_periph.c
CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)temperature_sensor_periph.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)temperature_sensor_periph.c
CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)spi_flash$(DELIM)flash_ops.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)spi_flash$(DELIM)flash_ops.c

View file

@ -109,6 +109,7 @@ CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$
CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)gpio_hal.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)gpio_hal.c
CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)ledc_hal_iram.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)ledc_hal_iram.c
CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)ledc_hal.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)ledc_hal.c
CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)pcnt_hal.c
CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)rmt_hal.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)rmt_hal.c
CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)mcpwm_hal.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)mcpwm_hal.c
CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)timer_hal.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)hal$(DELIM)timer_hal.c
@ -121,6 +122,7 @@ CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)log$
CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)log$(DELIM)log.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)log$(DELIM)log.c
CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)gpio_periph.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)gpio_periph.c
CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)ledc_periph.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)ledc_periph.c
CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)pcnt_periph.c
CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)rmt_periph.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)rmt_periph.c
CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)mcpwm_periph.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)mcpwm_periph.c
CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)temperature_sensor_periph.c CHIP_CSRCS += chip$(DELIM)$(ESP_HAL_3RDPARTY_REPO)$(DELIM)components$(DELIM)soc$(DELIM)$(CHIP_SERIES)$(DELIM)temperature_sensor_periph.c

View file

@ -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 */

View file

@ -38,8 +38,8 @@ ifeq ($(CONFIG_ESP32_I2S),y)
CSRCS += esp32_board_i2sdev.c CSRCS += esp32_board_i2sdev.c
endif endif
ifeq ($(CONFIG_ESP32_PCNT_AS_QE),y) ifeq ($(CONFIG_ESP_PCNT),y)
CSRCS += esp32_qencoder.c CSRCS += esp32_board_pcnt.c
endif endif
ifeq ($(CONFIG_SENSORS_MAX6675),y) ifeq ($(CONFIG_SENSORS_MAX6675),y)

View file

@ -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;
}

View file

@ -70,6 +70,11 @@
# include "board_qencoder.h" # include "board_qencoder.h"
#endif #endif
#ifdef CONFIG_ESP_PCNT
# include "espressif/esp_pcnt.h"
# include "esp32_board_pcnt.h"
#endif
#ifdef CONFIG_ESP32_RT_TIMER #ifdef CONFIG_ESP32_RT_TIMER
# include "esp32_rt_timer.h" # include "esp32_rt_timer.h"
#endif #endif
@ -357,6 +362,14 @@ int esp32_bringup(void)
} }
#endif #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 #ifdef CONFIG_RTC_DRIVER
/* Instantiate the ESP32 RTC driver */ /* Instantiate the ESP32 RTC driver */

View file

@ -94,8 +94,9 @@
# include "esp32_i2s.h" # include "esp32_i2s.h"
#endif #endif
#ifdef CONFIG_ESP32_PCNT_AS_QE #ifdef CONFIG_ESP_PCNT
# include "board_qencoder.h" # include "espressif/esp_pcnt.h"
# include "esp32_board_pcnt.h"
#endif #endif
#ifdef CONFIG_I2CMULTIPLEXER_TCA9548A #ifdef CONFIG_I2CMULTIPLEXER_TCA9548A
@ -475,16 +476,11 @@ int esp32_bringup(void)
} }
#endif #endif
#ifdef CONFIG_SENSORS_QENCODER #ifdef CONFIG_ESP_PCNT
/* Initialize and register the qencoder driver */ ret = board_pcnt_initialize();
if (ret < 0)
ret = board_qencoder_initialize(0, PCNT_QE0_ID);
if (ret != OK)
{ {
syslog(LOG_ERR, syslog(LOG_ERR, "ERROR: board_pcnt_initialize failed: %d\n", ret);
"ERROR: Failed to register the qencoder: %d\n",
ret);
return ret;
} }
#endif #endif

View file

@ -0,0 +1,79 @@
/****************************************************************************
* boards/xtensa/esp32s2/common/include/esp32s2_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_ESP32S2_COMMON_INCLUDE_ESP32S2_BOARD_PCNT_H
#define __BOARDS_XTENSA_ESP32S2_COMMON_INCLUDE_ESP32S2_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_ESP32S2_COMMON_INCLUDE_ESP32S2_BOARD_PCNT_H */

View file

@ -78,6 +78,10 @@ ifeq ($(CONFIG_ESP_RMT),y)
CSRCS += esp32s2_board_rmt.c CSRCS += esp32s2_board_rmt.c
endif endif
ifeq ($(CONFIG_ESP_PCNT),y)
CSRCS += esp32s2_board_pcnt.c
endif
ifeq ($(CONFIG_ESP32S2_TWAI)$(CONFIG_ARCH_BUTTONS),y) ifeq ($(CONFIG_ESP32S2_TWAI)$(CONFIG_ARCH_BUTTONS),y)
CHIP_SERIES = $(patsubst "%",%,$(CONFIG_ESPRESSIF_CHIP_SERIES)) CHIP_SERIES = $(patsubst "%",%,$(CONFIG_ESPRESSIF_CHIP_SERIES))
CHIPHALDIR = $(TOPDIR)$(DELIM)arch$(DELIM)$(CONFIG_ARCH)$(DELIM)src$(DELIM)chip$(DELIM)esp-hal-3rdparty CHIPHALDIR = $(TOPDIR)$(DELIM)arch$(DELIM)$(CONFIG_ARCH)$(DELIM)src$(DELIM)chip$(DELIM)esp-hal-3rdparty

View file

@ -0,0 +1,332 @@
/****************************************************************************
* boards/xtensa/esp32s2/common/src/esp32s2_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;
}

View file

@ -102,6 +102,11 @@
# include "espressif/esp_temperature_sensor.h" # include "espressif/esp_temperature_sensor.h"
#endif #endif
#ifdef CONFIG_ESP_PCNT
# include "espressif/esp_pcnt.h"
# include "esp32s2_board_pcnt.h"
#endif
#ifdef CONFIG_SYSTEM_NXDIAG_ESPRESSIF_CHIP_WO_TOOL #ifdef CONFIG_SYSTEM_NXDIAG_ESPRESSIF_CHIP_WO_TOOL
# include "espressif/esp_nxdiag.h" # include "espressif/esp_nxdiag.h"
#endif #endif
@ -417,6 +422,14 @@ int esp32s2_bringup(void)
} }
#endif #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 #ifdef CONFIG_RTC_DRIVER
/* Instantiate the ESP32 RTC driver */ /* Instantiate the ESP32 RTC driver */

View file

@ -0,0 +1,79 @@
/****************************************************************************
* boards/xtensa/esp32s3/common/include/esp32s3_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_ESP32S3_COMMON_INCLUDE_ESP32S3_BOARD_PCNT_H
#define __BOARDS_XTENSA_ESP32S3_COMMON_INCLUDE_ESP32S3_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_ESP32S3_COMMON_INCLUDE_ESP32S3_BOARD_PCNT_H */

View file

@ -74,6 +74,10 @@ ifeq ($(CONFIG_NET_LAN9250),y)
CSRCS += esp32s3_lan9250.c CSRCS += esp32s3_lan9250.c
endif endif
ifeq ($(CONFIG_ESP_PCNT),y)
CSRCS += esp32s3_board_pcnt.c
endif
ifeq ($(CONFIG_ESP_RMT),y) ifeq ($(CONFIG_ESP_RMT),y)
CSRCS += esp32s3_board_rmt.c CSRCS += esp32s3_board_rmt.c
endif endif

View file

@ -0,0 +1,332 @@
/****************************************************************************
* boards/xtensa/esp32s3/common/src/esp32s3_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;
}

View file

@ -130,6 +130,11 @@
# include "espressif/esp_temperature_sensor.h" # include "espressif/esp_temperature_sensor.h"
#endif #endif
#ifdef CONFIG_ESP_PCNT
# include "espressif/esp_pcnt.h"
# include "esp32s3_board_pcnt.h"
#endif
#ifdef CONFIG_SYSTEM_NXDIAG_ESPRESSIF_CHIP_WO_TOOL #ifdef CONFIG_SYSTEM_NXDIAG_ESPRESSIF_CHIP_WO_TOOL
# include "espressif/esp_nxdiag.h" # include "espressif/esp_nxdiag.h"
#endif #endif
@ -541,6 +546,14 @@ int esp32s3_bringup(void)
} }
#endif #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_SYSTEM_NXDIAG_ESPRESSIF_CHIP_WO_TOOL #ifdef CONFIG_SYSTEM_NXDIAG_ESPRESSIF_CHIP_WO_TOOL
ret = esp_nxdiag_initialize(); ret = esp_nxdiag_initialize();
if (ret < 0) if (ret < 0)