mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
example: update capture example with new driver API
This commit is contained in:
parent
b77446b5c8
commit
6751b229f1
@ -1,14 +1,15 @@
|
||||
| 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.)
|
||||
|
||||
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.
|
||||
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 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.
|
||||
|
||||
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:
|
||||
|
||||
@ -30,8 +31,8 @@ Echo +-----+
|
||||
|
||||
### Hardware Required
|
||||
|
||||
* An ESP development board
|
||||
* HC-SR04 module
|
||||
* An ESP development board that features the MCPWM peripheral
|
||||
* An HC-SR04 sensor module
|
||||
|
||||
Connection :
|
||||
|
||||
@ -60,21 +61,24 @@ See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/l
|
||||
## Example Output
|
||||
|
||||
```
|
||||
I (314) hc-sr04: HC-SR04 example based on capture function from MCPWM
|
||||
I (324) hc-sr04: Echo pin configured
|
||||
I (324) gpio: GPIO[19]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
|
||||
I (334) hc-sr04: Trig pin configured
|
||||
I (344) hc-sr04: trig task started
|
||||
I (444) hc-sr04: Pulse width: 419us, Measured distance: 7.22cm
|
||||
I (544) hc-sr04: Pulse width: 419us, Measured distance: 7.22cm
|
||||
I (644) hc-sr04: Pulse width: 416us, Measured distance: 7.17cm
|
||||
I (744) hc-sr04: Pulse width: 415us, Measured distance: 7.16cm
|
||||
I (844) hc-sr04: Pulse width: 415us, Measured distance: 7.16cm
|
||||
I (944) hc-sr04: Pulse width: 416us, Measured distance: 7.17cm
|
||||
I (1044) hc-sr04: Pulse width: 391us, Measured distance: 6.74cm
|
||||
I (0) cpu_start: Starting scheduler on APP CPU.
|
||||
I (304) example: Create capture queue
|
||||
I (304) example: Install capture timer
|
||||
I (304) example: Install capture channel
|
||||
I (314) gpio: GPIO[2]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
|
||||
I (324) example: Register capture callback
|
||||
I (324) example: Create a timer to trig HC_SR04 periodically
|
||||
I (334) example: Configure Trig pin
|
||||
I (334) gpio: GPIO[0]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
|
||||
I (344) example: Enable and start capture timer
|
||||
I (434) example: Pulse width: 189.02us, Measured distance: 3.26cm
|
||||
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
|
||||
|
||||
|
@ -6,119 +6,111 @@
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_private/esp_clk.h"
|
||||
#include "driver/mcpwm.h"
|
||||
#include "driver/mcpwm_cap.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!");
|
||||
#define HC_SR04_PIN_ECHO GPIO_NUM_18
|
||||
#define HC_SR04_PIN_TRIG GPIO_NUM_19
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////// Please update the following configuration according to your board spec ////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#define HC_SR04_TRIG_GPIO 0
|
||||
#define HC_SR04_ECHO_GPIO 2
|
||||
|
||||
#define TRIGGER_THREAD_STACK_SIZE 512
|
||||
#define TRIGGER_THREAD_PRIORITY 5
|
||||
|
||||
typedef struct {
|
||||
uint32_t capture_signal;
|
||||
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.
|
||||
static bool hc_sr04_echo_callback(mcpwm_cap_channel_handle_t cap_chan, const mcpwm_capture_event_data_t *edata, void *user_data)
|
||||
{
|
||||
static uint32_t cap_val_begin_of_sample = 0;
|
||||
static uint32_t cap_val_end_of_sample = 0;
|
||||
TaskHandle_t task_to_notify = (TaskHandle_t)user_data;
|
||||
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
|
||||
cap_val_begin_of_sample = edata->cap_value;
|
||||
cap_val_end_of_sample = cap_val_begin_of_sample;
|
||||
} else {
|
||||
cap_val_end_of_sample = edata->cap_value;
|
||||
// following formula refers to: https://www.elecrow.com/download/HC_SR04%20Datasheet.pdf
|
||||
uint32_t pulse_count = cap_val_end_of_sample - cap_val_begin_of_sample;
|
||||
// send measurement back though queue
|
||||
xQueueSendFromISR(cap_queue, &pulse_count, &high_task_wakeup);
|
||||
uint32_t tof_ticks = cap_val_end_of_sample - cap_val_begin_of_sample;
|
||||
|
||||
// notify the task to calculate the distance
|
||||
xTaskNotifyFromISR(task_to_notify, tof_ticks, eSetValueWithOverwrite, &high_task_wakeup);
|
||||
}
|
||||
|
||||
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
|
||||
cap_queue = xQueueCreate(1, sizeof(uint32_t));
|
||||
if (cap_queue == NULL) {
|
||||
ESP_LOGE(TAG, "failed to alloc cap_queue");
|
||||
return;
|
||||
}
|
||||
|
||||
/* 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
|
||||
void app_main(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "Install capture timer");
|
||||
mcpwm_cap_timer_handle_t cap_timer = NULL;
|
||||
mcpwm_capture_timer_config_t cap_conf = {
|
||||
.clk_src = MCPWM_CAPTURE_CLK_SRC_DEFAULT,
|
||||
.group_id = 0,
|
||||
};
|
||||
ESP_ERROR_CHECK(mcpwm_capture_enable_channel(MCPWM_UNIT_0, MCPWM_SELECT_CAP0, &conf));
|
||||
ESP_LOGI(TAG, "Echo pin configured");
|
||||
ESP_ERROR_CHECK(mcpwm_new_capture_timer(&cap_conf, &cap_timer));
|
||||
|
||||
/* 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 = {
|
||||
.intr_type = GPIO_INTR_DISABLE,
|
||||
.mode = GPIO_MODE_OUTPUT,
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||
.pull_up_en = GPIO_PULLUP_DISABLE,
|
||||
.pin_bit_mask = BIT64(HC_SR04_PIN_TRIG),
|
||||
.pin_bit_mask = 1ULL << HC_SR04_TRIG_GPIO,
|
||||
};
|
||||
ESP_ERROR_CHECK(gpio_config(&io_conf));
|
||||
ESP_ERROR_CHECK(gpio_set_level(HC_SR04_PIN_TRIG, 0)); // drive low by default
|
||||
ESP_LOGI(TAG, "Trig pin configured");
|
||||
// drive low by default
|
||||
ESP_ERROR_CHECK(gpio_set_level(HC_SR04_TRIG_GPIO, 0));
|
||||
|
||||
// start generating trig signal
|
||||
xTaskCreate(gen_trig_output, "gen_trig_output", TRIGGER_THREAD_STACK_SIZE, NULL, TRIGGER_THREAD_PRIORITY, NULL);
|
||||
ESP_LOGI(TAG, "trig task started");
|
||||
// forever loop
|
||||
while (true) {
|
||||
uint32_t pulse_count;
|
||||
// block and wait for new measurement
|
||||
xQueueReceive(cap_queue, &pulse_count, portMAX_DELAY);
|
||||
uint32_t pulse_width_us = pulse_count * (1000000.0 / esp_clk_apb_freq());
|
||||
// following formula is based on: https://www.elecrow.com/download/HC_SR04%20Datasheet.pdf
|
||||
if (pulse_width_us > 35000) {
|
||||
// out of range
|
||||
continue;
|
||||
ESP_LOGI(TAG, "Enable and start capture timer");
|
||||
ESP_ERROR_CHECK(mcpwm_capture_timer_enable(cap_timer));
|
||||
ESP_ERROR_CHECK(mcpwm_capture_timer_start(cap_timer));
|
||||
|
||||
uint32_t tof_ticks;
|
||||
while (1) {
|
||||
// trigger the sensor to start a new sample
|
||||
gen_trig_output();
|
||||
// wait for echo done signal
|
||||
if (xTaskNotifyWait(0x00, ULONG_MAX, &tof_ticks, pdMS_TO_TICKS(1000)) == pdTRUE) {
|
||||
float pulse_width_us = tof_ticks * (1000000.0 / esp_clk_apb_freq());
|
||||
if (pulse_width_us > 35000) {
|
||||
// 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;
|
||||
ESP_LOGI(TAG, "Pulse width: %uus, Measured distance: %.2fcm", pulse_width_us, distance);
|
||||
vTaskDelay(pdMS_TO_TICKS(500));
|
||||
}
|
||||
}
|
||||
|
@ -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')
|
Loading…
x
Reference in New Issue
Block a user