mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
225 lines
7.5 KiB
C
225 lines
7.5 KiB
C
/* Pulse counter module - Example
|
|
|
|
For other examples please check:
|
|
https://github.com/espressif/esp-idf/tree/master/examples
|
|
|
|
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
|
|
|
Unless required by applicable law or agreed to in writing, this
|
|
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
|
CONDITIONS OF ANY KIND, either express or implied.
|
|
*/
|
|
#include <stdio.h>
|
|
#include "freertos/FreeRTOS.h"
|
|
#include "freertos/portmacro.h"
|
|
#include "freertos/task.h"
|
|
#include "freertos/queue.h"
|
|
#include "driver/periph_ctrl.h"
|
|
#include "driver/ledc.h"
|
|
#include "driver/gpio.h"
|
|
#include "driver/pcnt.h"
|
|
#include "esp_attr.h"
|
|
#include "esp_log.h"
|
|
#include "soc/gpio_sig_map.h"
|
|
|
|
/**
|
|
* TEST CODE BRIEF
|
|
* Use PCNT module to count rising edges generated by LEDC module.
|
|
* GPIO18 is used as output pin, GPIO4 is used as pulse input pin and GPIO5 is used as control input pin
|
|
*
|
|
* Open serial port to view the message printed on your screen
|
|
*
|
|
* To do this test, you should connect GPIO18 with GPIO4
|
|
* GPIO5 is the control signal, you can leave it floating with internal pulled up, or connect it to ground.
|
|
* If you connect gpio5 to GND ,you will found the count value decreasing.
|
|
*
|
|
* When counter value reaches thresh1 or thresh0 value, it will trigger interrupt.
|
|
* When counter value reaches l_lim value or h_lim value, counter value will be reset to zero and trigger interrupt.
|
|
*/
|
|
#define PCNT_TEST_UNIT PCNT_UNIT_0
|
|
#define PCNT_H_LIM_VAL 10
|
|
#define PCNT_L_LIM_VAL -10
|
|
#define PCNT_THRESH1_VAL 5
|
|
#define PCNT_THRESH0_VAL -5
|
|
#define PCNT_INPUT_SIG_IO 4 /* Pulse Input GPIO */
|
|
#define PCNT_INPUT_CTRL_IO 5 /* Control GPIO HIGH=count up, LOW=count down */
|
|
#define LEDC_OUTPUT_IO 18 /* Output GPIO */
|
|
|
|
xQueueHandle pcnt_evt_queue; /*A queue to handle pulse counter event*/
|
|
|
|
|
|
typedef struct {
|
|
int unit; /*pulse counter unit*/
|
|
uint32_t status; /*pulse counter internal status*/
|
|
} pcnt_evt_t;
|
|
|
|
void IRAM_ATTR pcnt_intr_handler(void* arg)
|
|
{
|
|
uint32_t intr_status = PCNT.int_st.val;
|
|
int i;
|
|
pcnt_evt_t evt;
|
|
portBASE_TYPE HPTaskAwoken = pdFALSE;
|
|
|
|
for(i = 0; i < PCNT_UNIT_MAX; i++) {
|
|
if(intr_status & (BIT(i))) {
|
|
evt.unit = i;
|
|
evt.status = PCNT.status_unit[i].val;
|
|
PCNT.int_clr.val = BIT(i);
|
|
/*H LIM EVT*/
|
|
if(PCNT.status_unit[i].h_lim_lat) {
|
|
//do something
|
|
}
|
|
/*L LIM EVT*/
|
|
if(PCNT.status_unit[i].l_lim_lat) {
|
|
//do something
|
|
}
|
|
/*THRES0 EVT*/
|
|
if(PCNT.status_unit[i].thres0_lat) {
|
|
//do something
|
|
}
|
|
/*THRES1 EVT*/
|
|
if(PCNT.status_unit[i].thres1_lat) {
|
|
//do something
|
|
}
|
|
/*ZERO EVT*/
|
|
if(PCNT.status_unit[i].zero_lat) {
|
|
//do something
|
|
}
|
|
xQueueSendFromISR(pcnt_evt_queue, &evt, &HPTaskAwoken);
|
|
if(HPTaskAwoken == pdTRUE) {
|
|
portYIELD_FROM_ISR();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void ledc_init(void)
|
|
{
|
|
ledc_channel_config_t ledc_channel;
|
|
/*use LEDC_OUTPUT_IO as output pin*/
|
|
ledc_channel.gpio_num = LEDC_OUTPUT_IO;
|
|
/*LEDC high speed mode */
|
|
ledc_channel.speed_mode = LEDC_HIGH_SPEED_MODE;
|
|
/*use LEDC channel 1*/
|
|
ledc_channel.channel = LEDC_CHANNEL_1;
|
|
/*Disable LEDC interrupt*/
|
|
ledc_channel.intr_type = LEDC_INTR_DISABLE;
|
|
/*Select LEDC timer 1 */
|
|
ledc_channel.timer_sel = LEDC_TIMER_1;
|
|
/*Set duty 100 */
|
|
ledc_channel.duty = 100;
|
|
ledc_channel_config(&ledc_channel); //ledc config
|
|
|
|
ledc_timer_config_t ledc_timer;
|
|
/*LEDC timer high speed mode*/
|
|
ledc_timer.speed_mode = LEDC_HIGH_SPEED_MODE;
|
|
/*10 bit PWM*/
|
|
ledc_timer.bit_num = LEDC_TIMER_10_BIT;
|
|
/*Select timer 1*/
|
|
ledc_timer.timer_num = LEDC_TIMER_1;
|
|
/*Set frequency 1 Hz */
|
|
ledc_timer.freq_hz = 1;
|
|
ledc_timer_config(&ledc_timer);
|
|
}
|
|
|
|
static void pcnt_init(void)
|
|
{
|
|
pcnt_config_t pcnt_config = {
|
|
/*Set PCNT_INPUT_SIG_IO as pulse input gpio */
|
|
.pulse_gpio_num = PCNT_INPUT_SIG_IO,
|
|
/*set PCNT_INPUT_CTRL_IO as control gpio */
|
|
.ctrl_gpio_num = PCNT_INPUT_CTRL_IO,
|
|
/*Choose channel 0 */
|
|
.channel = PCNT_CHANNEL_0,
|
|
/*Choose unit 0 */
|
|
.unit = PCNT_TEST_UNIT,
|
|
/*Set counter and control mode*/
|
|
/*Counter increase for positive edge on pulse input GPIO*/
|
|
.pos_mode = PCNT_COUNT_INC,
|
|
/*Counter decrease for negative edge on pulse input GPIO*/
|
|
.neg_mode = PCNT_COUNT_DIS, //keep the counter value
|
|
/*Counter mode reverse when control input is low level*/
|
|
.lctrl_mode = PCNT_MODE_REVERSE,
|
|
/*Counter mode does not change when control input is high level*/
|
|
.hctrl_mode = PCNT_MODE_KEEP, //when control signal is high,keep the primary counter mode
|
|
/*Set maximum value for increasing counter*/
|
|
.counter_h_lim = PCNT_H_LIM_VAL,
|
|
/*Set minimum value for decreasing counter*/
|
|
.counter_l_lim = PCNT_L_LIM_VAL,
|
|
};
|
|
/*Initialize PCNT unit */
|
|
pcnt_unit_config(&pcnt_config);
|
|
|
|
/*Configure input filter value*/
|
|
pcnt_set_filter_value(PCNT_TEST_UNIT, 100);
|
|
/*Enable input filter*/
|
|
pcnt_filter_enable(PCNT_TEST_UNIT);
|
|
|
|
/*Set value for watch point thresh1*/
|
|
pcnt_set_event_value(PCNT_TEST_UNIT, PCNT_EVT_THRES_1, PCNT_THRESH1_VAL);
|
|
/*Enable watch point event of thresh1*/
|
|
pcnt_event_enable(PCNT_TEST_UNIT, PCNT_EVT_THRES_1);
|
|
/*Set value for watch point thresh0*/
|
|
pcnt_set_event_value(PCNT_TEST_UNIT, PCNT_EVT_THRES_0, PCNT_THRESH0_VAL);
|
|
/*Enable watch point event of thresh0*/
|
|
pcnt_event_enable(PCNT_TEST_UNIT, PCNT_EVT_THRES_0);
|
|
/*Enable watch point event of h_lim*/
|
|
pcnt_event_enable(PCNT_TEST_UNIT, PCNT_EVT_H_LIM);
|
|
/*Enable watch point event of l_lim*/
|
|
pcnt_event_enable(PCNT_TEST_UNIT, PCNT_EVT_L_LIM);
|
|
/*Enable watch point event of zero*/
|
|
pcnt_event_enable(PCNT_TEST_UNIT, PCNT_EVT_ZERO);
|
|
|
|
/*Pause counter*/
|
|
pcnt_counter_pause(PCNT_TEST_UNIT);
|
|
/*Reset counter value*/
|
|
pcnt_counter_clear(PCNT_TEST_UNIT);
|
|
/*Register ISR handler*/
|
|
pcnt_isr_register(pcnt_intr_handler, NULL, 0, NULL);
|
|
/*Enable interrupt for PCNT unit*/
|
|
pcnt_intr_enable(PCNT_TEST_UNIT);
|
|
/*Resume counting*/
|
|
pcnt_counter_resume(PCNT_TEST_UNIT);
|
|
}
|
|
|
|
void app_main()
|
|
{
|
|
/*Init LEDC for pulse input signal */
|
|
ledc_init();
|
|
/*Init PCNT event queue */
|
|
pcnt_evt_queue = xQueueCreate(10, sizeof(pcnt_evt_t));
|
|
/*Init PCNT functions*/
|
|
pcnt_init();
|
|
|
|
int16_t count = 0;
|
|
pcnt_evt_t evt;
|
|
portBASE_TYPE res;
|
|
while(1)
|
|
{
|
|
res = xQueueReceive(pcnt_evt_queue, &evt, 1000 / portTICK_PERIOD_MS);
|
|
if(res == pdTRUE) {
|
|
pcnt_get_counter_value(PCNT_TEST_UNIT, &count);
|
|
printf("Event PCNT unit[%d]; cnt: %d\n", evt.unit, count);
|
|
if(evt.status & PCNT_STATUS_THRES1_M) {
|
|
printf("THRES1 EVT\n");
|
|
}
|
|
if(evt.status & PCNT_STATUS_THRES0_M) {
|
|
printf("THRES0 EVT\n");
|
|
}
|
|
if(evt.status & PCNT_STATUS_L_LIM_M) {
|
|
printf("L_LIM EVT\n");
|
|
}
|
|
if(evt.status & PCNT_STATUS_H_LIM_M) {
|
|
printf("H_LIM EVT\n");
|
|
}
|
|
if(evt.status & PCNT_STATUS_ZERO_M) {
|
|
printf("ZERO EVT\n");
|
|
}
|
|
} else {
|
|
pcnt_get_counter_value(PCNT_TEST_UNIT, &count);
|
|
printf("Current counter value :%d\n", count);
|
|
}
|
|
}
|
|
}
|
|
|