forked from espressif/esp-idf
example: update capture example with new driver API
This commit is contained in:
@@ -1,14 +1,15 @@
|
|||||||
| Supported Targets | ESP32 | ESP32-S3 |
|
| Supported Targets | ESP32 | ESP32-S3 |
|
||||||
| ----------------- | ----- | -------- |
|
| ----------------- | ----- | -------- |
|
||||||
|
|
||||||
# HC-SR04 Example
|
# HC-SR04 Example based on MCPWM Capture
|
||||||
|
|
||||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||||
|
|
||||||
The capture module in MCPWM peripheral is designed to accurately log the time stamp on the hardware side when an event happens (compared to GPIO ISR which requires a software-based logging method). Each capture unit has three channels, which can be used together to capture IO events parallelly.
|
The capture module in MCPWM peripheral is designed to accurately log the time stamp on the hardware side when an event happens (compared to GPIO ISR which requires a software-based logging method). Each capture unit has three channels, which can be used together to capture IO events in parallel.
|
||||||
This example shows how to make use of the HW features to decode the pulse width signals generated from a common HC-SR04 sonar range finder -- [HC-SR04](https://www.sparkfun.com/products/15569).
|
|
||||||
|
|
||||||
The signal that HC-SR04 produces (and what can be handled by this example) is a simple pulse whose width indicates the measured distance. A pulse is required to send to HC-SR04 on `Trig` pin to begin a new measurement. Then the pulse described above will be sent back on `Echo` pin for decoding.
|
This example shows how to make use of the hardware features to decode the pulse width signals generated from a common HC-SR04 sonar sensor -- [HC-SR04](https://www.sparkfun.com/products/15569).
|
||||||
|
|
||||||
|
The signal that HC-SR04 produces (and what can be handled by this example) is a simple pulse whose width indicates the measured distance. An excitation pulse is required to send to HC-SR04 on `Trig` pin to begin a new measurement. Then the pulse described above will appear on the `Echo` pin after a while.
|
||||||
|
|
||||||
Typical signals:
|
Typical signals:
|
||||||
|
|
||||||
@@ -30,8 +31,8 @@ Echo +-----+
|
|||||||
|
|
||||||
### Hardware Required
|
### Hardware Required
|
||||||
|
|
||||||
* An ESP development board
|
* An ESP development board that features the MCPWM peripheral
|
||||||
* HC-SR04 module
|
* An HC-SR04 sensor module
|
||||||
|
|
||||||
Connection :
|
Connection :
|
||||||
|
|
||||||
@@ -60,21 +61,24 @@ See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/l
|
|||||||
## Example Output
|
## Example Output
|
||||||
|
|
||||||
```
|
```
|
||||||
I (314) hc-sr04: HC-SR04 example based on capture function from MCPWM
|
I (0) cpu_start: Starting scheduler on APP CPU.
|
||||||
I (324) hc-sr04: Echo pin configured
|
I (304) example: Create capture queue
|
||||||
I (324) gpio: GPIO[19]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
|
I (304) example: Install capture timer
|
||||||
I (334) hc-sr04: Trig pin configured
|
I (304) example: Install capture channel
|
||||||
I (344) hc-sr04: trig task started
|
I (314) gpio: GPIO[2]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
|
||||||
I (444) hc-sr04: Pulse width: 419us, Measured distance: 7.22cm
|
I (324) example: Register capture callback
|
||||||
I (544) hc-sr04: Pulse width: 419us, Measured distance: 7.22cm
|
I (324) example: Create a timer to trig HC_SR04 periodically
|
||||||
I (644) hc-sr04: Pulse width: 416us, Measured distance: 7.17cm
|
I (334) example: Configure Trig pin
|
||||||
I (744) hc-sr04: Pulse width: 415us, Measured distance: 7.16cm
|
I (334) gpio: GPIO[0]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
|
||||||
I (844) hc-sr04: Pulse width: 415us, Measured distance: 7.16cm
|
I (344) example: Enable and start capture timer
|
||||||
I (944) hc-sr04: Pulse width: 416us, Measured distance: 7.17cm
|
I (434) example: Pulse width: 189.02us, Measured distance: 3.26cm
|
||||||
I (1044) hc-sr04: Pulse width: 391us, Measured distance: 6.74cm
|
I (534) example: Pulse width: 189.02us, Measured distance: 3.26cm
|
||||||
|
I (634) example: Pulse width: 189.01us, Measured distance: 3.26cm
|
||||||
|
I (734) example: Pulse width: 188.98us, Measured distance: 3.26cm
|
||||||
|
I (834) example: Pulse width: 188.99us, Measured distance: 3.26cm
|
||||||
```
|
```
|
||||||
|
|
||||||
This example runs at 10Hz sampling rate. out of range data is dropped and only valid measurement is printed.
|
This example runs at 10Hz sampling rate. Measure data that out of the range is dropped and only valid measurement is printed out.
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
|
@@ -6,119 +6,111 @@
|
|||||||
|
|
||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
#include "freertos/task.h"
|
#include "freertos/task.h"
|
||||||
#include "freertos/queue.h"
|
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
#include "esp_private/esp_clk.h"
|
#include "esp_private/esp_clk.h"
|
||||||
#include "driver/mcpwm.h"
|
#include "driver/mcpwm_cap.h"
|
||||||
#include "driver/gpio.h"
|
#include "driver/gpio.h"
|
||||||
|
|
||||||
const static char *TAG = "hc-sr04";
|
const static char *TAG = "example";
|
||||||
|
|
||||||
#define HC_SR04_SAMPLE_PERIOD_MS 100
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
_Static_assert(HC_SR04_SAMPLE_PERIOD_MS > 50, "Sample period too short!");
|
//////////////////// Please update the following configuration according to your board spec ////////////////////////////
|
||||||
#define HC_SR04_PIN_ECHO GPIO_NUM_18
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
#define HC_SR04_PIN_TRIG GPIO_NUM_19
|
#define HC_SR04_TRIG_GPIO 0
|
||||||
|
#define HC_SR04_ECHO_GPIO 2
|
||||||
|
|
||||||
#define TRIGGER_THREAD_STACK_SIZE 512
|
static bool hc_sr04_echo_callback(mcpwm_cap_channel_handle_t cap_chan, const mcpwm_capture_event_data_t *edata, void *user_data)
|
||||||
#define TRIGGER_THREAD_PRIORITY 5
|
{
|
||||||
|
static uint32_t cap_val_begin_of_sample = 0;
|
||||||
typedef struct {
|
static uint32_t cap_val_end_of_sample = 0;
|
||||||
uint32_t capture_signal;
|
TaskHandle_t task_to_notify = (TaskHandle_t)user_data;
|
||||||
mcpwm_capture_signal_t sel_cap_signal;
|
|
||||||
} capture;
|
|
||||||
|
|
||||||
static uint32_t cap_val_begin_of_sample = 0;
|
|
||||||
static uint32_t cap_val_end_of_sample = 0;
|
|
||||||
|
|
||||||
static QueueHandle_t cap_queue;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief generate single pulse on Trig pin to activate a new sample
|
|
||||||
*/
|
|
||||||
static void gen_trig_output(void *arg) {
|
|
||||||
TickType_t xLastWakeTime = xTaskGetTickCount();
|
|
||||||
while (true) {
|
|
||||||
vTaskDelayUntil(&xLastWakeTime, HC_SR04_SAMPLE_PERIOD_MS / portTICK_PERIOD_MS);
|
|
||||||
ESP_ERROR_CHECK(gpio_set_level(HC_SR04_PIN_TRIG, 1)); // set high
|
|
||||||
esp_rom_delay_us(10);
|
|
||||||
ESP_ERROR_CHECK(gpio_set_level(HC_SR04_PIN_TRIG, 0)); // set low
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief this is an ISR callback, we take action according to the captured edge
|
|
||||||
*/
|
|
||||||
static bool sr04_echo_isr_handler(mcpwm_unit_t mcpwm, mcpwm_capture_channel_id_t cap_sig, const cap_event_data_t *edata,
|
|
||||||
void *arg) {
|
|
||||||
//calculate the interval in the ISR,
|
|
||||||
//so that the interval will be always correct even when cap_queue is not handled in time and overflow.
|
|
||||||
BaseType_t high_task_wakeup = pdFALSE;
|
BaseType_t high_task_wakeup = pdFALSE;
|
||||||
if (edata->cap_edge == MCPWM_POS_EDGE) {
|
|
||||||
|
//calculate the interval in the ISR,
|
||||||
|
//so that the interval will be always correct even when capture_queue is not handled in time and overflow.
|
||||||
|
if (edata->cap_edge == MCPWM_CAP_EDGE_POS) {
|
||||||
// store the timestamp when pos edge is detected
|
// store the timestamp when pos edge is detected
|
||||||
cap_val_begin_of_sample = edata->cap_value;
|
cap_val_begin_of_sample = edata->cap_value;
|
||||||
cap_val_end_of_sample = cap_val_begin_of_sample;
|
cap_val_end_of_sample = cap_val_begin_of_sample;
|
||||||
} else {
|
} else {
|
||||||
cap_val_end_of_sample = edata->cap_value;
|
cap_val_end_of_sample = edata->cap_value;
|
||||||
// following formula refers to: https://www.elecrow.com/download/HC_SR04%20Datasheet.pdf
|
uint32_t tof_ticks = cap_val_end_of_sample - cap_val_begin_of_sample;
|
||||||
uint32_t pulse_count = cap_val_end_of_sample - cap_val_begin_of_sample;
|
|
||||||
// send measurement back though queue
|
// notify the task to calculate the distance
|
||||||
xQueueSendFromISR(cap_queue, &pulse_count, &high_task_wakeup);
|
xTaskNotifyFromISR(task_to_notify, tof_ticks, eSetValueWithOverwrite, &high_task_wakeup);
|
||||||
}
|
}
|
||||||
|
|
||||||
return high_task_wakeup == pdTRUE;
|
return high_task_wakeup == pdTRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void app_main(void) {
|
/**
|
||||||
ESP_LOGI(TAG, "HC-SR04 example based on capture function from MCPWM");
|
* @brief generate single pulse on Trig pin to start a new sample
|
||||||
|
*/
|
||||||
|
static void gen_trig_output(void)
|
||||||
|
{
|
||||||
|
gpio_set_level(HC_SR04_TRIG_GPIO, 1); // set high
|
||||||
|
esp_rom_delay_us(10);
|
||||||
|
gpio_set_level(HC_SR04_TRIG_GPIO, 0); // set low
|
||||||
|
}
|
||||||
|
|
||||||
// the queue where we read data
|
void app_main(void)
|
||||||
cap_queue = xQueueCreate(1, sizeof(uint32_t));
|
{
|
||||||
if (cap_queue == NULL) {
|
ESP_LOGI(TAG, "Install capture timer");
|
||||||
ESP_LOGE(TAG, "failed to alloc cap_queue");
|
mcpwm_cap_timer_handle_t cap_timer = NULL;
|
||||||
return;
|
mcpwm_capture_timer_config_t cap_conf = {
|
||||||
}
|
.clk_src = MCPWM_CAPTURE_CLK_SRC_DEFAULT,
|
||||||
|
.group_id = 0,
|
||||||
/* configure Echo pin */
|
|
||||||
// set CAP_0 on GPIO
|
|
||||||
ESP_ERROR_CHECK(mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM_CAP_0, HC_SR04_PIN_ECHO));
|
|
||||||
// enable pull down CAP0, to reduce noise
|
|
||||||
ESP_ERROR_CHECK(gpio_pulldown_en(HC_SR04_PIN_ECHO));
|
|
||||||
// enable both edge capture on CAP0
|
|
||||||
mcpwm_capture_config_t conf = {
|
|
||||||
.cap_edge = MCPWM_BOTH_EDGE,
|
|
||||||
.cap_prescale = 1,
|
|
||||||
.capture_cb = sr04_echo_isr_handler,
|
|
||||||
.user_data = NULL
|
|
||||||
};
|
};
|
||||||
ESP_ERROR_CHECK(mcpwm_capture_enable_channel(MCPWM_UNIT_0, MCPWM_SELECT_CAP0, &conf));
|
ESP_ERROR_CHECK(mcpwm_new_capture_timer(&cap_conf, &cap_timer));
|
||||||
ESP_LOGI(TAG, "Echo pin configured");
|
|
||||||
|
|
||||||
/* configure Trig pin */
|
ESP_LOGI(TAG, "Install capture channel");
|
||||||
|
mcpwm_cap_channel_handle_t cap_chan = NULL;
|
||||||
|
mcpwm_capture_channel_config_t cap_ch_conf = {
|
||||||
|
.gpio_num = HC_SR04_ECHO_GPIO,
|
||||||
|
.prescale = 1,
|
||||||
|
// capture on both edge
|
||||||
|
.flags.neg_edge = true,
|
||||||
|
.flags.pos_edge = true,
|
||||||
|
// pull up internally
|
||||||
|
.flags.pull_up = true,
|
||||||
|
};
|
||||||
|
ESP_ERROR_CHECK(mcpwm_new_capture_channel(cap_timer, &cap_ch_conf, &cap_chan));
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "Register capture callback");
|
||||||
|
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
|
||||||
|
mcpwm_capture_event_callbacks_t cbs = {
|
||||||
|
.on_cap = hc_sr04_echo_callback,
|
||||||
|
};
|
||||||
|
ESP_ERROR_CHECK(mcpwm_capture_channel_register_event_callbacks(cap_chan, &cbs, cur_task));
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "Configure Trig pin");
|
||||||
gpio_config_t io_conf = {
|
gpio_config_t io_conf = {
|
||||||
.intr_type = GPIO_INTR_DISABLE,
|
|
||||||
.mode = GPIO_MODE_OUTPUT,
|
.mode = GPIO_MODE_OUTPUT,
|
||||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
.pin_bit_mask = 1ULL << HC_SR04_TRIG_GPIO,
|
||||||
.pull_up_en = GPIO_PULLUP_DISABLE,
|
|
||||||
.pin_bit_mask = BIT64(HC_SR04_PIN_TRIG),
|
|
||||||
};
|
};
|
||||||
ESP_ERROR_CHECK(gpio_config(&io_conf));
|
ESP_ERROR_CHECK(gpio_config(&io_conf));
|
||||||
ESP_ERROR_CHECK(gpio_set_level(HC_SR04_PIN_TRIG, 0)); // drive low by default
|
// drive low by default
|
||||||
ESP_LOGI(TAG, "Trig pin configured");
|
ESP_ERROR_CHECK(gpio_set_level(HC_SR04_TRIG_GPIO, 0));
|
||||||
|
|
||||||
// start generating trig signal
|
ESP_LOGI(TAG, "Enable and start capture timer");
|
||||||
xTaskCreate(gen_trig_output, "gen_trig_output", TRIGGER_THREAD_STACK_SIZE, NULL, TRIGGER_THREAD_PRIORITY, NULL);
|
ESP_ERROR_CHECK(mcpwm_capture_timer_enable(cap_timer));
|
||||||
ESP_LOGI(TAG, "trig task started");
|
ESP_ERROR_CHECK(mcpwm_capture_timer_start(cap_timer));
|
||||||
// forever loop
|
|
||||||
while (true) {
|
uint32_t tof_ticks;
|
||||||
uint32_t pulse_count;
|
while (1) {
|
||||||
// block and wait for new measurement
|
// trigger the sensor to start a new sample
|
||||||
xQueueReceive(cap_queue, &pulse_count, portMAX_DELAY);
|
gen_trig_output();
|
||||||
uint32_t pulse_width_us = pulse_count * (1000000.0 / esp_clk_apb_freq());
|
// wait for echo done signal
|
||||||
// following formula is based on: https://www.elecrow.com/download/HC_SR04%20Datasheet.pdf
|
if (xTaskNotifyWait(0x00, ULONG_MAX, &tof_ticks, pdMS_TO_TICKS(1000)) == pdTRUE) {
|
||||||
if (pulse_width_us > 35000) {
|
float pulse_width_us = tof_ticks * (1000000.0 / esp_clk_apb_freq());
|
||||||
// out of range
|
if (pulse_width_us > 35000) {
|
||||||
continue;
|
// out of range
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// convert the pulse width into measure distance
|
||||||
|
float distance = (float) pulse_width_us / 58;
|
||||||
|
ESP_LOGI(TAG, "Measured distance: %.2fcm", distance);
|
||||||
}
|
}
|
||||||
float distance = (float) pulse_width_us / 58;
|
vTaskDelay(pdMS_TO_TICKS(500));
|
||||||
ESP_LOGI(TAG, "Pulse width: %uus, Measured distance: %.2fcm", pulse_width_us, distance);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,16 @@
|
|||||||
|
# SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||||
|
# SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
from pytest_embedded import Dut
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.esp32
|
||||||
|
@pytest.mark.esp32s3
|
||||||
|
@pytest.mark.generic
|
||||||
|
def test_hc_sr04_example(dut: Dut) -> None:
|
||||||
|
dut.expect_exact('example: Install capture timer')
|
||||||
|
dut.expect_exact('example: Install capture channel')
|
||||||
|
dut.expect_exact('example: Register capture callback')
|
||||||
|
dut.expect_exact('example: Configure Trig pin')
|
||||||
|
dut.expect_exact('example: Enable and start capture timer')
|
Reference in New Issue
Block a user