mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'bugfix/rmt_one-wire_v5.1' into 'release/v5.1'
rmt_onewire: refactor example with component registry (v5.1) See merge request espressif/esp-idf!23509
This commit is contained in:
commit
2004bf4e11
@ -500,7 +500,7 @@ static bool IRAM_ATTR rmt_isr_handle_rx_done(rmt_rx_channel_t *rx_chan)
|
|||||||
rmt_ll_rx_enable(hal->regs, channel_id, false);
|
rmt_ll_rx_enable(hal->regs, channel_id, false);
|
||||||
uint32_t offset = rmt_ll_rx_get_memory_writer_offset(hal->regs, channel_id);
|
uint32_t offset = rmt_ll_rx_get_memory_writer_offset(hal->regs, channel_id);
|
||||||
// sanity check
|
// sanity check
|
||||||
assert(offset > rx_chan->mem_off);
|
assert(offset >= rx_chan->mem_off);
|
||||||
rmt_ll_rx_set_mem_owner(hal->regs, channel_id, RMT_LL_MEM_OWNER_SW);
|
rmt_ll_rx_set_mem_owner(hal->regs, channel_id, RMT_LL_MEM_OWNER_SW);
|
||||||
// copy the symbols to user space
|
// copy the symbols to user space
|
||||||
size_t stream_symbols = offset - rx_chan->mem_off;
|
size_t stream_symbols = offset - rx_chan->mem_off;
|
||||||
|
@ -518,7 +518,7 @@ Application Examples
|
|||||||
* RMT transactions in queue: :example:`peripherals/rmt/musical_buzzer`
|
* RMT transactions in queue: :example:`peripherals/rmt/musical_buzzer`
|
||||||
* RMT based stepper motor with S-curve algorithm: : :example:`peripherals/rmt/stepper_motor`
|
* RMT based stepper motor with S-curve algorithm: : :example:`peripherals/rmt/stepper_motor`
|
||||||
* RMT infinite loop for driving DShot ESC: :example:`peripherals/rmt/dshot_esc`
|
* RMT infinite loop for driving DShot ESC: :example:`peripherals/rmt/dshot_esc`
|
||||||
* RMT simulate 1-wire protocol (take DS18B20 as example): :example:`peripherals/rmt/onewire_ds18b20`
|
* RMT simulate 1-wire protocol (take DS18B20 as example): :example:`peripherals/rmt/onewire`
|
||||||
|
|
||||||
API Reference
|
API Reference
|
||||||
-------------
|
-------------
|
||||||
|
@ -3,4 +3,4 @@
|
|||||||
cmake_minimum_required(VERSION 3.16)
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
|
||||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||||
project(onewire_ds18b20)
|
project(onewire)
|
74
examples/peripherals/rmt/onewire/README.md
Normal file
74
examples/peripherals/rmt/onewire/README.md
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 |
|
||||||
|
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- |
|
||||||
|
|
||||||
|
# Advanced RMT Transmit & Receive Example -- Simulate 1-Wire Bus
|
||||||
|
|
||||||
|
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||||
|
|
||||||
|
RMT peripheral has independent transmit and receive channels. We can simulate the [1-Wire](https://www.analog.com/en/technical-articles/guide-to-1wire-communication.html) bus by attaching a pair of transmit and receive channel to the same GPIO, and turning on the open-drain mode of the GPIO pad.
|
||||||
|
|
||||||
|
We've made the 1-Wire protocol implementation into a component called `onewire_bus`, which has been uploaded to the [component registry](https://components.espressif.com/components/espressif/onewire_bus).
|
||||||
|
|
||||||
|
This example demonstrates how to use that `onewire_bus` library to read temperature from the [DS18B20](https://www.analog.com/media/en/technical-documentation/data-sheets/ds18b20.pdf) sensor. Likewise, the DS18B20 device is also made as a single component and pushed to the [component registry](https://components.espressif.com/components/espressif/ds18b20).
|
||||||
|
|
||||||
|
One of the amazing feature that offered by the `onewire_bus` driver is that, is can support enumerate the devices on the bus, thus you can connect multiple DS18B20 sensors to the same bus and read their temperature one by one.
|
||||||
|
|
||||||
|
## How to Use Example
|
||||||
|
|
||||||
|
### Hardware Required
|
||||||
|
|
||||||
|
* A development board with any supported Espressif SOC chip (see `Supported Targets` table above)
|
||||||
|
* One or more DS18B20 sensors connected to the same bus by a 4.7 KΩ pull-up resistor
|
||||||
|
|
||||||
|
Connection :
|
||||||
|
|
||||||
|
```plain
|
||||||
|
┌──────────────────────────┐
|
||||||
|
│ 3.3V├───────┬─────────────┬──────────────────────┐
|
||||||
|
│ │ ┌┴┐ │VDD │VDD
|
||||||
|
│ ESP Board │ 4.7k│ │ ┌──────┴──────┐ ┌──────┴──────┐
|
||||||
|
│ │ └┬┘ DQ│ │ DQ│ │
|
||||||
|
│ ONEWIRE_GPIO_PIN├───────┴──┬───┤ DS18B20 │ ┌───┤ DS18B20 │ ......
|
||||||
|
│ │ └───│-------------│────┴───│-------------│──
|
||||||
|
│ │ └──────┬──────┘ └──────┬──────┘
|
||||||
|
│ │ │GND │GND
|
||||||
|
│ GND├─────────────────────┴──────────────────────┘
|
||||||
|
└──────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
The GPIO number used in this example can be changed according to your board, by the macro `EXAMPLE_ONEWIRE_BUS_GPIO` defined in [onewire_example_main.c](main/onewire_example_main.c).
|
||||||
|
|
||||||
|
> **Note**
|
||||||
|
> Parasite power mode is not supported, you have to connect VDD pin to make DS18B20 functional.
|
||||||
|
|
||||||
|
### Build and Flash
|
||||||
|
|
||||||
|
Run `idf.py -p PORT flash monitor` to build, flash and monitor the project.
|
||||||
|
|
||||||
|
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||||
|
|
||||||
|
See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects.
|
||||||
|
|
||||||
|
## Console Output
|
||||||
|
|
||||||
|
```plain
|
||||||
|
I (340) main_task: Started on CPU0
|
||||||
|
I (350) main_task: Calling app_main()
|
||||||
|
I (350) gpio: GPIO[0]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
|
||||||
|
I (360) gpio: GPIO[0]| InputEn: 1| OutputEn: 1| OpenDrain: 1| Pullup: 1| Pulldown: 0| Intr:0
|
||||||
|
I (370) example: 1-Wire bus installed on GPIO0
|
||||||
|
I (370) example: Device iterator created, start searching...
|
||||||
|
I (490) example: Found a DS18B20[0], address: 070822502019FC28
|
||||||
|
I (590) example: Found a DS18B20[1], address: FC0921C076034628
|
||||||
|
I (590) example: Searching done, 2 DS18B20 device(s) found
|
||||||
|
I (1620) example: temperature read from DS18B20[0]: 22.50C
|
||||||
|
I (2430) example: temperature read from DS18B20[1]: 22.81C
|
||||||
|
I (3440) example: temperature read from DS18B20[0]: 22.50C
|
||||||
|
I (4250) example: temperature read from DS18B20[1]: 22.81C
|
||||||
|
I (5260) example: temperature read from DS18B20[0]: 22.50C
|
||||||
|
I (6070) example: temperature read from DS18B20[1]: 22.81C
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon.
|
2
examples/peripherals/rmt/onewire/main/CMakeLists.txt
Normal file
2
examples/peripherals/rmt/onewire/main/CMakeLists.txt
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
idf_component_register(SRCS "onewire_example_main.c"
|
||||||
|
INCLUDE_DIRS ".")
|
2
examples/peripherals/rmt/onewire/main/idf_component.yml
Normal file
2
examples/peripherals/rmt/onewire/main/idf_component.yml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
dependencies:
|
||||||
|
ds18b20: "^0.1.0"
|
76
examples/peripherals/rmt/onewire/main/onewire_example_main.c
Normal file
76
examples/peripherals/rmt/onewire/main/onewire_example_main.c
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||||
|
*/
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "esp_check.h"
|
||||||
|
#include "onewire_bus.h"
|
||||||
|
#include "ds18b20.h"
|
||||||
|
|
||||||
|
static const char *TAG = "example";
|
||||||
|
|
||||||
|
#define EXAMPLE_ONEWIRE_BUS_GPIO 0
|
||||||
|
#define EXAMPLE_ONEWIRE_MAX_DS18B20 2
|
||||||
|
|
||||||
|
void app_main(void)
|
||||||
|
{
|
||||||
|
// install new 1-wire bus
|
||||||
|
onewire_bus_handle_t bus;
|
||||||
|
onewire_bus_config_t bus_config = {
|
||||||
|
.bus_gpio_num = EXAMPLE_ONEWIRE_BUS_GPIO,
|
||||||
|
};
|
||||||
|
onewire_bus_rmt_config_t rmt_config = {
|
||||||
|
.max_rx_bytes = 10, // 1byte ROM command + 8byte ROM number + 1byte device command
|
||||||
|
};
|
||||||
|
ESP_ERROR_CHECK(onewire_new_bus_rmt(&bus_config, &rmt_config, &bus));
|
||||||
|
ESP_LOGI(TAG, "1-Wire bus installed on GPIO%d", EXAMPLE_ONEWIRE_BUS_GPIO);
|
||||||
|
|
||||||
|
int ds18b20_device_num = 0;
|
||||||
|
ds18b20_device_handle_t ds18b20s[EXAMPLE_ONEWIRE_MAX_DS18B20];
|
||||||
|
onewire_device_iter_handle_t iter = NULL;
|
||||||
|
onewire_device_t next_onewire_device;
|
||||||
|
esp_err_t search_result = ESP_OK;
|
||||||
|
|
||||||
|
// create 1-wire device iterator, which is used for device search
|
||||||
|
ESP_ERROR_CHECK(onewire_new_device_iter(bus, &iter));
|
||||||
|
ESP_LOGI(TAG, "Device iterator created, start searching...");
|
||||||
|
do {
|
||||||
|
search_result = onewire_device_iter_get_next(iter, &next_onewire_device);
|
||||||
|
if (search_result == ESP_OK) { // found a new device, let's check if we can upgrade it to a DS18B20
|
||||||
|
ds18b20_config_t ds_cfg = {};
|
||||||
|
if (ds18b20_new_device(&next_onewire_device, &ds_cfg, &ds18b20s[ds18b20_device_num]) == ESP_OK) {
|
||||||
|
ESP_LOGI(TAG, "Found a DS18B20[%d], address: %016llX", ds18b20_device_num, next_onewire_device.address);
|
||||||
|
ds18b20_device_num++;
|
||||||
|
if (ds18b20_device_num >= EXAMPLE_ONEWIRE_MAX_DS18B20) {
|
||||||
|
ESP_LOGI(TAG, "Max DS18B20 number reached, stop searching...");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ESP_LOGI(TAG, "Found an unknown device, address: %016llX", next_onewire_device.address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (search_result != ESP_ERR_NOT_FOUND);
|
||||||
|
ESP_ERROR_CHECK(onewire_del_device_iter(iter));
|
||||||
|
ESP_LOGI(TAG, "Searching done, %d DS18B20 device(s) found", ds18b20_device_num);
|
||||||
|
|
||||||
|
// set resolution for all DS18B20s
|
||||||
|
for (int i = 0; i < ds18b20_device_num; i++) {
|
||||||
|
// set resolution
|
||||||
|
ESP_ERROR_CHECK(ds18b20_set_resolution(ds18b20s[i], DS18B20_RESOLUTION_12B));
|
||||||
|
}
|
||||||
|
|
||||||
|
// get temperature from sensors one by one
|
||||||
|
float temperature;
|
||||||
|
while (1) {
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(200));
|
||||||
|
|
||||||
|
for (int i = 0; i < ds18b20_device_num; i ++) {
|
||||||
|
ESP_ERROR_CHECK(ds18b20_trigger_temperature_conversion(ds18b20s[i]));
|
||||||
|
ESP_ERROR_CHECK(ds18b20_get_temperature(ds18b20s[i], &temperature));
|
||||||
|
ESP_LOGI(TAG, "temperature read from DS18B20[%d]: %.2fC", i, temperature);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -11,8 +11,7 @@ from pytest_embedded import Dut
|
|||||||
@pytest.mark.esp32c6
|
@pytest.mark.esp32c6
|
||||||
@pytest.mark.esp32h2
|
@pytest.mark.esp32h2
|
||||||
@pytest.mark.generic
|
@pytest.mark.generic
|
||||||
def test_onewire_ds18b20_example(dut: Dut) -> None:
|
def test_onewire_example(dut: Dut) -> None:
|
||||||
dut.expect_exact('onewire_rmt: RMT Tx channel created for 1-wire bus')
|
dut.expect_exact('example: 1-Wire bus installed on GPIO')
|
||||||
dut.expect_exact('onewire_rmt: RMT Rx channel created for 1-wire bus')
|
dut.expect_exact('example: Device iterator created, start searching')
|
||||||
dut.expect_exact('example: 1-wire bus installed')
|
dut.expect_exact('example: Searching done')
|
||||||
dut.expect_exact('example: 1-wire bus deleted')
|
|
@ -1,90 +0,0 @@
|
|||||||
| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 |
|
|
||||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- |
|
|
||||||
|
|
||||||
# RMT Transmit & Receive Example -- 1-Wire bus
|
|
||||||
|
|
||||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
|
||||||
|
|
||||||
RMT peripheral has both transmit and receive channels. Connecting one transmit channel and one receive channel to the same GPIO and put the GPIO in open-drain mode can simulate bi-directional single wire protocols, such as [1-Wire protocol](https://www.maximintegrated.com/en/design/technical-documents/tutorials/1/1796.html).
|
|
||||||
|
|
||||||
This example demonstrates how to use RMT to simulate 1-Wire bus and read temperatrue from [DS18B20](https://datasheets.maximintegrated.com/en/ds/DS18B20.pdf).
|
|
||||||
|
|
||||||
## How to Use Example
|
|
||||||
|
|
||||||
### Hardware Required
|
|
||||||
|
|
||||||
* A development board with any supported Espressif SOC chip (see `Supported Targets` table above)
|
|
||||||
* Several DS18B20 temperature sensors and a 4.7kohm pullup resistor
|
|
||||||
|
|
||||||
Connection :
|
|
||||||
|
|
||||||
```
|
|
||||||
┌──────────────────────────┐
|
|
||||||
│ 3.3V├───────┬─────────────┬──────────────────────┐
|
|
||||||
│ │ ┌┴┐ │VDD │VDD
|
|
||||||
│ ESP32 Board │ 4.7k│ │ ┌──────┴──────┐ ┌──────┴──────┐
|
|
||||||
│ │ └┬┘ DQ│ │ DQ│ │
|
|
||||||
│ ONEWIRE_GPIO_PIN├───────┴──┬───┤ DS18B20 │ ┌───┤ DS18B20 │ ......
|
|
||||||
│ │ └───│-------------│────┴───│-------------│──
|
|
||||||
│ │ └──────┬──────┘ └──────┬──────┘
|
|
||||||
│ │ │GND │GND
|
|
||||||
│ GND├─────────────────────┴──────────────────────┘
|
|
||||||
└──────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
The GPIO number used in this example can be changed according to your board, by the macro `EXAMPLE_ONEWIRE_GPIO_PIN` defined in [onewire_ds18b20_example_main.c](main/onewire_ds18b20_example_main.c).
|
|
||||||
|
|
||||||
*Note*: Parasite power mode is not supported currently by this example, you have to connect VDD pin to make DS18B20 functional.
|
|
||||||
|
|
||||||
### Build and Flash
|
|
||||||
|
|
||||||
Run `idf.py -p PORT flash monitor` to build, flash and monitor the project.
|
|
||||||
|
|
||||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
|
||||||
|
|
||||||
See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects.
|
|
||||||
|
|
||||||
## Console Output
|
|
||||||
|
|
||||||
If there are some DS18B20s on the bus:
|
|
||||||
|
|
||||||
```
|
|
||||||
I (327) cpu_start: Starting scheduler on PRO CPU.
|
|
||||||
I (0) cpu_start: Starting scheduler on APP CPU.
|
|
||||||
I (338) gpio: GPIO[5]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
|
|
||||||
I (348) onewire_rmt: RMT Tx channel created for 1-wire bus
|
|
||||||
I (358) gpio: GPIO[5]| InputEn: 1| OutputEn: 1| OpenDrain: 1| Pullup: 1| Pulldown: 0| Intr:0
|
|
||||||
I (358) onewire_rmt: RMT Rx channel created for 1-wire bus
|
|
||||||
I (368) example: 1-wire bus installed
|
|
||||||
I (418) example: found device with rom id 28FF30BE21170317
|
|
||||||
I (458) example: found device with rom id 28FF297E211703A1
|
|
||||||
I (498) example: found device with rom id 28FF6F7921170352
|
|
||||||
I (508) example: 3 devices found on 1-wire bus
|
|
||||||
I (2518) example: temperature of device 28FF30BE21170317: 27.00C
|
|
||||||
I (2528) example: temperature of device 28FF297E211703A1: 26.81C
|
|
||||||
I (2538) example: temperature of device 28FF6F7921170352: 26.50C
|
|
||||||
I (3548) example: temperature of device 28FF30BE21170317: 26.94C
|
|
||||||
I (3558) example: temperature of device 28FF297E211703A1: 26.75C
|
|
||||||
I (3568) example: temperature of device 28FF6F7921170352: 26.44C
|
|
||||||
```
|
|
||||||
|
|
||||||
If there is no DS18B20 on the bus:
|
|
||||||
|
|
||||||
```
|
|
||||||
I (327) cpu_start: Starting scheduler on PRO CPU.
|
|
||||||
I (0) cpu_start: Starting scheduler on APP CPU.
|
|
||||||
I (337) gpio: GPIO[5]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
|
|
||||||
I (347) onewire_rmt: RMT Tx channel created for 1-wire bus
|
|
||||||
I (357) gpio: GPIO[5]| InputEn: 1| OutputEn: 1| OpenDrain: 1| Pullup: 1| Pulldown: 0| Intr:0
|
|
||||||
I (357) onewire_rmt: RMT Rx channel created for 1-wire bus
|
|
||||||
I (367) example: 1-wire bus installed
|
|
||||||
E (377) onewire_rmt: no device present on 1-wire bus
|
|
||||||
I (377) example: 0 device found on 1-wire bus
|
|
||||||
I (387) gpio: GPIO[5]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
|
|
||||||
I (397) gpio: GPIO[5]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
|
|
||||||
I (397) example: 1-wire bus deleted
|
|
||||||
```
|
|
||||||
|
|
||||||
## Troubleshooting
|
|
||||||
|
|
||||||
For any technical queries, please open an [issue] (https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon.
|
|
@ -1,3 +0,0 @@
|
|||||||
idf_component_register(SRCS "onewire_bus_rmt.c" "onewire_bus.c"
|
|
||||||
INCLUDE_DIRS "."
|
|
||||||
PRIV_REQUIRES driver)
|
|
@ -1,158 +0,0 @@
|
|||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
#include <string.h>
|
|
||||||
#include "esp_check.h"
|
|
||||||
#include "esp_log.h"
|
|
||||||
#include "onewire_bus.h"
|
|
||||||
|
|
||||||
static const char *TAG = "onewire";
|
|
||||||
|
|
||||||
struct onewire_rom_search_context_t {
|
|
||||||
onewire_bus_handle_t bus_handle;
|
|
||||||
|
|
||||||
uint8_t last_device_flag;
|
|
||||||
uint16_t last_discrepancy;
|
|
||||||
uint8_t rom_number[8];
|
|
||||||
};
|
|
||||||
|
|
||||||
// Algorithm inspired by https://www.maximintegrated.com/en/design/technical-documents/app-notes/1/187.html
|
|
||||||
|
|
||||||
static const uint8_t dscrc_table[] = {
|
|
||||||
0, 94,188,226, 97, 63,221,131,194,156,126, 32,163,253, 31, 65,
|
|
||||||
157,195, 33,127,252,162, 64, 30, 95, 1,227,189, 62, 96,130,220,
|
|
||||||
35,125,159,193, 66, 28,254,160,225,191, 93, 3,128,222, 60, 98,
|
|
||||||
190,224, 2, 92,223,129, 99, 61,124, 34,192,158, 29, 67,161,255,
|
|
||||||
70, 24,250,164, 39,121,155,197,132,218, 56,102,229,187, 89, 7,
|
|
||||||
219,133,103, 57,186,228, 6, 88, 25, 71,165,251,120, 38,196,154,
|
|
||||||
101, 59,217,135, 4, 90,184,230,167,249, 27, 69,198,152,122, 36,
|
|
||||||
248,166, 68, 26,153,199, 37,123, 58,100,134,216, 91, 5,231,185,
|
|
||||||
140,210, 48,110,237,179, 81, 15, 78, 16,242,172, 47,113,147,205,
|
|
||||||
17, 79,173,243,112, 46,204,146,211,141,111, 49,178,236, 14, 80,
|
|
||||||
175,241, 19, 77,206,144,114, 44,109, 51,209,143, 12, 82,176,238,
|
|
||||||
50,108,142,208, 83, 13,239,177,240,174, 76, 18,145,207, 45,115,
|
|
||||||
202,148,118, 40,171,245, 23, 73, 8, 86,180,234,105, 55,213,139,
|
|
||||||
87, 9,235,181, 54,104,138,212,149,203, 41,119,244,170, 72, 22,
|
|
||||||
233,183, 85, 11,136,214, 52,106, 43,117,151,201, 74, 20,246,168,
|
|
||||||
116, 42,200,150, 21, 75,169,247,182,232, 10, 84,215,137,107, 53
|
|
||||||
};
|
|
||||||
|
|
||||||
uint8_t onewire_check_crc8(uint8_t *input, size_t input_size)
|
|
||||||
{
|
|
||||||
uint8_t crc8 = 0;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < input_size; i ++) {
|
|
||||||
crc8 = dscrc_table[crc8 ^ input[i]];
|
|
||||||
}
|
|
||||||
|
|
||||||
return crc8;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t onewire_rom_search_context_create(onewire_bus_handle_t handle, onewire_rom_search_context_handler_t *context_out)
|
|
||||||
{
|
|
||||||
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid 1-wire handle");
|
|
||||||
ESP_RETURN_ON_FALSE(context_out, ESP_ERR_INVALID_ARG, TAG, "invalid context handler pointer");
|
|
||||||
|
|
||||||
struct onewire_rom_search_context_t *context = calloc(1, sizeof(struct onewire_rom_search_context_t));
|
|
||||||
if (!context) {
|
|
||||||
return ESP_ERR_NO_MEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
context->bus_handle = handle;
|
|
||||||
*context_out = context;
|
|
||||||
|
|
||||||
return ESP_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t onewire_rom_search_context_delete(onewire_rom_search_context_handler_t context)
|
|
||||||
{
|
|
||||||
ESP_RETURN_ON_FALSE(context, ESP_ERR_INVALID_ARG, TAG, "invalid context handler pointer");
|
|
||||||
|
|
||||||
free(context);
|
|
||||||
|
|
||||||
return ESP_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t onewire_rom_search(onewire_rom_search_context_handler_t context)
|
|
||||||
{
|
|
||||||
ESP_RETURN_ON_FALSE(context, ESP_ERR_INVALID_ARG, TAG, "invalid context handler pointer");
|
|
||||||
|
|
||||||
uint8_t last_zero = 0;
|
|
||||||
|
|
||||||
if (!context->last_device_flag) {
|
|
||||||
if (onewire_bus_reset(context->bus_handle) != ESP_OK) { // no device present
|
|
||||||
return ESP_ERR_NOT_FOUND;
|
|
||||||
}
|
|
||||||
|
|
||||||
// send rom search command and start search algorithm
|
|
||||||
ESP_RETURN_ON_ERROR(onewire_bus_write_bytes(context->bus_handle, (uint8_t[]){ONEWIRE_CMD_SEARCH_ROM}, 1),
|
|
||||||
TAG, "error while sending search rom command");
|
|
||||||
|
|
||||||
for (uint16_t rom_bit_index = 0; rom_bit_index < 64; rom_bit_index ++) {
|
|
||||||
uint8_t rom_byte_index = rom_bit_index / 8;
|
|
||||||
uint8_t rom_bit_mask = 1 << (rom_bit_index % 8); // calculate byte index and bit mask in advance for convenience
|
|
||||||
|
|
||||||
uint8_t rom_bit, rom_bit_complement;
|
|
||||||
ESP_RETURN_ON_ERROR(onewire_bus_read_bit(context->bus_handle, &rom_bit), TAG, "error while reading rom bit"); // write 1 bit to read from the bus
|
|
||||||
ESP_RETURN_ON_ERROR(onewire_bus_read_bit(context->bus_handle, &rom_bit_complement),
|
|
||||||
TAG, "error while reading rom bit"); // read a bit and its complement
|
|
||||||
|
|
||||||
uint8_t search_direction;
|
|
||||||
if (rom_bit && rom_bit_complement) { // No devices participating in search.
|
|
||||||
ESP_LOGE(TAG, "no devices participating in search");
|
|
||||||
return ESP_ERR_NOT_FOUND;
|
|
||||||
} else {
|
|
||||||
if (rom_bit != rom_bit_complement) { // There are only 0s or 1s in the bit of the participating ROM numbers.
|
|
||||||
search_direction = rom_bit; // just go ahead
|
|
||||||
} else { // There are both 0s and 1s in the current bit position of the participating ROM numbers. This is a discrepancy.
|
|
||||||
if (rom_bit_index < context->last_discrepancy) { // current id bit is before the last discrepancy bit
|
|
||||||
search_direction = (context->rom_number[rom_byte_index] & rom_bit_mask) ? 0x01 : 0x00; // follow previous way
|
|
||||||
} else {
|
|
||||||
search_direction = (rom_bit_index == context->last_discrepancy) ? 0x01 : 0x00; // search for 0 bit first
|
|
||||||
}
|
|
||||||
|
|
||||||
if (search_direction == 0) { // record zero's position in last zero
|
|
||||||
last_zero = rom_bit_index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (search_direction == 1) { // set corrsponding rom bit by serach direction
|
|
||||||
context->rom_number[rom_byte_index] |= rom_bit_mask;
|
|
||||||
} else {
|
|
||||||
context->rom_number[rom_byte_index] &= ~rom_bit_mask;
|
|
||||||
}
|
|
||||||
|
|
||||||
ESP_RETURN_ON_ERROR(onewire_bus_write_bit(context->bus_handle, search_direction),
|
|
||||||
TAG, "error while writing direction bit"); // set search direction
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ESP_LOGD(TAG, "1-wire rom search finished");
|
|
||||||
return ESP_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if the search was successful
|
|
||||||
context->last_discrepancy = last_zero;
|
|
||||||
if (context->last_discrepancy == 0) { // last zero loops back to the first bit
|
|
||||||
context->last_device_flag = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (onewire_check_crc8(context->rom_number, 7) != context->rom_number[7]) { // check crc
|
|
||||||
ESP_LOGE(TAG, "bad crc checksum of device with id " ONEWIRE_ROM_ID_STR, ONEWIRE_ROM_ID(context->rom_number));
|
|
||||||
return ESP_ERR_INVALID_CRC;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ESP_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t onewire_rom_get_number(onewire_rom_search_context_handler_t context, uint8_t *rom_number_out)
|
|
||||||
{
|
|
||||||
ESP_RETURN_ON_FALSE(context, ESP_ERR_INVALID_ARG, TAG, "invalid context pointer");
|
|
||||||
ESP_RETURN_ON_FALSE(rom_number_out, ESP_ERR_INVALID_ARG, TAG, "invalid rom_number pointer");
|
|
||||||
|
|
||||||
memcpy(rom_number_out, context->rom_number, sizeof(context->rom_number));
|
|
||||||
|
|
||||||
return ESP_OK;
|
|
||||||
}
|
|
@ -1,77 +0,0 @@
|
|||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "esp_err.h"
|
|
||||||
#include "onewire_bus_rmt.h"
|
|
||||||
|
|
||||||
#define ONEWIRE_CMD_SEARCH_ROM 0xF0
|
|
||||||
#define ONEWIRE_CMD_READ_ROM 0x33
|
|
||||||
#define ONEWIRE_CMD_MATCH_ROM 0x55
|
|
||||||
#define ONEWIRE_CMD_SKIP_ROM 0xCC
|
|
||||||
#define ONEWIRE_CMD_ALARM_SEARCH_ROM 0xEC
|
|
||||||
|
|
||||||
#define ONEWIRE_ROM_ID(id) (id)[0], (id)[1], (id)[2], (id)[3], (id)[4], (id)[5], (id)[6], (id)[7]
|
|
||||||
#define ONEWIRE_ROM_ID_STR "%02X%02X%02X%02X%02X%02X%02X%02X"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Type of 1-wire ROM search algorithm context
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
typedef struct onewire_rom_search_context_t *onewire_rom_search_context_handler_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Calculate Dallas CRC value of given buffer
|
|
||||||
*
|
|
||||||
* @param[in] input Input buffer to calculate CRC value
|
|
||||||
* @param[in] input_size Size of input buffer
|
|
||||||
* @return CRC result of input buffer
|
|
||||||
*/
|
|
||||||
uint8_t onewire_check_crc8(uint8_t *input, size_t input_size);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Create context for 1-wire ROM search algorithm
|
|
||||||
*
|
|
||||||
* @param[in] handle 1-wire handle used for ROM search
|
|
||||||
* @param[out] context_out Created context for ROM search algorithm
|
|
||||||
* @return
|
|
||||||
* - ESP_OK 1-wire ROM search context is created successfully.
|
|
||||||
* - ESP_ERR_INVALID_ARG Invalid argument.
|
|
||||||
*/
|
|
||||||
esp_err_t onewire_rom_search_context_create(onewire_bus_handle_t handle, onewire_rom_search_context_handler_t *context_out);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Delete context for 1-wire ROM search algorithm
|
|
||||||
*
|
|
||||||
* @param[in] context Context for ROM search algorithm
|
|
||||||
* @return
|
|
||||||
* - ESP_OK 1-wire ROM search context is deleted successfully.
|
|
||||||
* - ESP_ERR_INVALID_ARG Invalid argument.
|
|
||||||
*/
|
|
||||||
esp_err_t onewire_rom_search_context_delete(onewire_rom_search_context_handler_t context);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Search next device on 1-wire bus
|
|
||||||
*
|
|
||||||
* @param[in] context Context for ROM search algorithm
|
|
||||||
* @return
|
|
||||||
* - ESP_OK Successfully found a device
|
|
||||||
* - ESP_ERR_NOT_FOUND There are no device on the bus
|
|
||||||
* - ESP_ERR_INVALID_CRC Bad CRC value of found device
|
|
||||||
* - ESP_FAIL Reached last device on the bus, search algorighm finishes
|
|
||||||
*/
|
|
||||||
esp_err_t onewire_rom_search(onewire_rom_search_context_handler_t context);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get device ROM number from ROM search context
|
|
||||||
*
|
|
||||||
* @param[in] context Context for ROM search algorithm
|
|
||||||
* @param[out] rom_number_out Device ROM number
|
|
||||||
* @return
|
|
||||||
* - ESP_OK Get ROM numbuer from 1-wire ROM search context success.
|
|
||||||
* - ESP_ERR_INVALID_ARG Invalid argument.
|
|
||||||
*/
|
|
||||||
esp_err_t onewire_rom_get_number(onewire_rom_search_context_handler_t context, uint8_t *rom_number_out);
|
|
@ -1,438 +0,0 @@
|
|||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
#include <string.h>
|
|
||||||
#include "freertos/FreeRTOS.h"
|
|
||||||
#include "freertos/task.h"
|
|
||||||
#include "freertos/queue.h"
|
|
||||||
#include "esp_check.h"
|
|
||||||
#include "driver/rmt_tx.h"
|
|
||||||
#include "driver/rmt_rx.h"
|
|
||||||
#include "driver/rmt_types.h"
|
|
||||||
#include "driver/rmt_encoder.h"
|
|
||||||
#include "onewire_bus_rmt.h"
|
|
||||||
|
|
||||||
static const char *TAG = "onewire_rmt";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief RMT resolution for 1-wire bus, in Hz
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#define ONEWIRE_RMT_RESOLUTION_HZ 1000000
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 1-wire bus timing parameters, in us (1/ONEWIRE_RMT_RESOLUTION_HZ)
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#define ONEWIRE_RESET_PULSE_DURATION 500 // duration of reset bit
|
|
||||||
#define ONEWIRE_RESET_WAIT_DURATION 200 // how long should master wait for device to show its presence
|
|
||||||
#define ONEWIRE_RESET_PRESENSE_WAIT_DURATION_MIN 15 // minimum duration for master to wait device to show its presence
|
|
||||||
#define ONEWIRE_RESET_PRESENSE_DURATION_MIN 60 // minimum duration for master to recognize device as present
|
|
||||||
|
|
||||||
#define ONEWIRE_SLOT_START_DURATION 2 // bit start pulse duration
|
|
||||||
#define ONEWIRE_SLOT_BIT_DURATION 60 // duration for each bit to transmit
|
|
||||||
// refer to https://www.maximintegrated.com/en/design/technical-documents/app-notes/3/3829.html for more information
|
|
||||||
#define ONEWIRE_SLOT_RECOVERY_DURATION 2 // recovery time between each bit, should be longer in parasite power mode
|
|
||||||
#define ONEWIRE_SLOT_BIT_SAMPLE_TIME 15 // how long after bit start pulse should the master sample from the bus
|
|
||||||
|
|
||||||
/*
|
|
||||||
Reset Pulse:
|
|
||||||
|
|
||||||
| RESET_PULSE | RESET_WAIT_DURATION |
|
|
||||||
| _DURATION | |
|
|
||||||
| | | | RESET | |
|
|
||||||
| | * | | _PRESENSE | |
|
|
||||||
| | | | _DURATION | |
|
|
||||||
------────┐ ┌─────┐ ┌───────-------
|
|
||||||
│ │ │ │
|
|
||||||
│ │ │ │
|
|
||||||
│ │ │ │
|
|
||||||
└─────────────┘ └───────────┘
|
|
||||||
*: RESET_PRESENSE_WAIT_DURATION
|
|
||||||
|
|
||||||
Write 1 bit:
|
|
||||||
|
|
||||||
| SLOT_START | SLOT_BIT | SLOT_RECOVERY | NEXT
|
|
||||||
| _DURATION | _DURATION | _DURATION | SLOT
|
|
||||||
| | | |
|
|
||||||
------────┐ ┌───────────────────────────────------
|
|
||||||
│ │
|
|
||||||
│ │
|
|
||||||
│ │
|
|
||||||
└────────────┘
|
|
||||||
|
|
||||||
Write 0 bit:
|
|
||||||
|
|
||||||
| SLOT_START | SLOT_BIT | SLOT_RECOVERY | NEXT
|
|
||||||
| _DURATION | _DURATION | _DURATION | SLOT
|
|
||||||
| | | |
|
|
||||||
------────┐ ┌───────────────────------
|
|
||||||
│ │
|
|
||||||
│ │
|
|
||||||
│ │
|
|
||||||
└────────────────────────┘
|
|
||||||
|
|
||||||
Read 1 bit:
|
|
||||||
|
|
||||||
|
|
||||||
| SLOT_START | SLOT_BIT_DURATION | SLOT_RECOVERY | NEXT
|
|
||||||
| _DURATION | | _DURATION | SLOT
|
|
||||||
| | SLOT_BIT_ | | |
|
|
||||||
| | SAMPLE_TIME | | |
|
|
||||||
------────┐ ┌────────────────────────────────────────------
|
|
||||||
│ │
|
|
||||||
│ │
|
|
||||||
│ │
|
|
||||||
└────────────┘
|
|
||||||
|
|
||||||
Read 0 bit:
|
|
||||||
|
|
||||||
| SLOT_START | SLOT_BIT_DURATION | SLOT_RECOVERY | NEXT
|
|
||||||
| _DURATION | | _DURATION | SLOT
|
|
||||||
| | SLOT_BIT_ | | |
|
|
||||||
| | SAMPLE_TIME | | |
|
|
||||||
------────┐ | | ┌───────────────────────------
|
|
||||||
│ | │
|
|
||||||
│ | PULLED DOWN │
|
|
||||||
│ | BY DEVICE │
|
|
||||||
└─────────────────────────────┘
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct onewire_bus_t {
|
|
||||||
rmt_channel_handle_t tx_channel; /*!< rmt tx channel handler */
|
|
||||||
rmt_encoder_handle_t tx_bytes_encoder; /*!< used to encode commands and data */
|
|
||||||
rmt_encoder_handle_t tx_copy_encoder; /*!< used to encode reset pulse and bits */
|
|
||||||
|
|
||||||
rmt_channel_handle_t rx_channel; /*!< rmt rx channel handler */
|
|
||||||
rmt_symbol_word_t *rx_symbols; /*!< hold rmt raw symbols */
|
|
||||||
|
|
||||||
size_t max_rx_bytes; /*!< buffer size in byte for single receive transaction */
|
|
||||||
|
|
||||||
QueueHandle_t receive_queue;
|
|
||||||
};
|
|
||||||
|
|
||||||
const static rmt_symbol_word_t onewire_bit0_symbol = {
|
|
||||||
.level0 = 0,
|
|
||||||
.duration0 = ONEWIRE_SLOT_START_DURATION + ONEWIRE_SLOT_BIT_DURATION,
|
|
||||||
.level1 = 1,
|
|
||||||
.duration1 = ONEWIRE_SLOT_RECOVERY_DURATION
|
|
||||||
};
|
|
||||||
|
|
||||||
const static rmt_symbol_word_t onewire_bit1_symbol = {
|
|
||||||
.level0 = 0,
|
|
||||||
.duration0 = ONEWIRE_SLOT_START_DURATION,
|
|
||||||
.level1 = 1,
|
|
||||||
.duration1 = ONEWIRE_SLOT_BIT_DURATION + ONEWIRE_SLOT_RECOVERY_DURATION
|
|
||||||
};
|
|
||||||
|
|
||||||
const static rmt_symbol_word_t onewire_reset_pulse_symbol = {
|
|
||||||
.level0 = 0,
|
|
||||||
.duration0 = ONEWIRE_RESET_PULSE_DURATION,
|
|
||||||
.level1 = 1,
|
|
||||||
.duration1 = ONEWIRE_RESET_WAIT_DURATION
|
|
||||||
};
|
|
||||||
|
|
||||||
const static rmt_transmit_config_t onewire_rmt_tx_config = {
|
|
||||||
.loop_count = 0, // no transfer loop
|
|
||||||
.flags.eot_level = 1 // onewire bus should be released in IDLE
|
|
||||||
};
|
|
||||||
|
|
||||||
const static rmt_receive_config_t onewire_rmt_rx_config = {
|
|
||||||
.signal_range_min_ns = 1000000000 / ONEWIRE_RMT_RESOLUTION_HZ,
|
|
||||||
.signal_range_max_ns = (ONEWIRE_RESET_PULSE_DURATION + ONEWIRE_RESET_WAIT_DURATION) * 1000
|
|
||||||
};
|
|
||||||
|
|
||||||
static bool onewire_rmt_rx_done_callback(rmt_channel_handle_t channel, const rmt_rx_done_event_data_t *edata, void *user_data)
|
|
||||||
{
|
|
||||||
BaseType_t task_woken = pdFALSE;
|
|
||||||
struct onewire_bus_t *handle = (struct onewire_bus_t *)user_data;
|
|
||||||
|
|
||||||
xQueueSendFromISR(handle->receive_queue, edata, &task_woken);
|
|
||||||
|
|
||||||
return task_woken;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
[0].0 means symbol[0].duration0
|
|
||||||
|
|
||||||
First reset pulse after rmt channel init:
|
|
||||||
|
|
||||||
Bus is low | Reset | Wait | Device | Bus Idle
|
|
||||||
after init | Pulse | | Presense |
|
|
||||||
┌──────┐ ┌─────------
|
|
||||||
│ │ │
|
|
||||||
│ │ │
|
|
||||||
│ │ │
|
|
||||||
------─────────────┘ └──────────┘
|
|
||||||
1 2 3
|
|
||||||
|
|
||||||
[0].1 [0].0 [1].1 [1].0
|
|
||||||
|
|
||||||
|
|
||||||
Following reset pulses:
|
|
||||||
|
|
||||||
Bus is high | Reset | Wait | Device | Bus Idle
|
|
||||||
after init | Pulse | | Presense |
|
|
||||||
------──────┐ ┌──────┐ ┌─────------
|
|
||||||
│ │ │ │
|
|
||||||
│ │ │ │
|
|
||||||
│ │ │ │
|
|
||||||
└───────┘ └──────────┘
|
|
||||||
1 2 3 4
|
|
||||||
|
|
||||||
[0].0 [0].1 [1].0 [1].1
|
|
||||||
*/
|
|
||||||
|
|
||||||
static bool onewire_rmt_check_presence_pulse(rmt_symbol_word_t *rmt_symbols, size_t symbol_num)
|
|
||||||
{
|
|
||||||
if (symbol_num >= 2) { // there should be at lease 2 symbols(3 or 4 edges)
|
|
||||||
if (rmt_symbols[0].level1 == 1) { // bus is high before reset pulse
|
|
||||||
if (rmt_symbols[0].duration1 > ONEWIRE_RESET_PRESENSE_WAIT_DURATION_MIN &&
|
|
||||||
rmt_symbols[1].duration0 > ONEWIRE_RESET_PRESENSE_DURATION_MIN) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} else { // bus is low before reset pulse(first pulse after rmt channel init)
|
|
||||||
if (rmt_symbols[0].duration0 > ONEWIRE_RESET_PRESENSE_WAIT_DURATION_MIN &&
|
|
||||||
rmt_symbols[1].duration1 > ONEWIRE_RESET_PRESENSE_DURATION_MIN) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ESP_LOGE(TAG, "no device present on 1-wire bus");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void onewire_rmt_decode_data(rmt_symbol_word_t *rmt_symbols, size_t symbol_num, uint8_t *decoded_bytes)
|
|
||||||
{
|
|
||||||
size_t byte_pos = 0, bit_pos = 0;
|
|
||||||
for (size_t i = 0; i < symbol_num; i ++) {
|
|
||||||
if (rmt_symbols[i].duration0 > ONEWIRE_SLOT_BIT_SAMPLE_TIME) { // 0 bit
|
|
||||||
decoded_bytes[byte_pos] &= ~(1 << bit_pos); // LSB first
|
|
||||||
} else { // 1 bit
|
|
||||||
decoded_bytes[byte_pos] |= 1 << bit_pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
bit_pos ++;
|
|
||||||
if (bit_pos >= 8) {
|
|
||||||
bit_pos = 0;
|
|
||||||
byte_pos ++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t onewire_new_bus_rmt(onewire_rmt_config_t *config, onewire_bus_handle_t *handle_out)
|
|
||||||
{
|
|
||||||
ESP_RETURN_ON_FALSE(config, ESP_ERR_INVALID_ARG, TAG, "invalid config pointer");
|
|
||||||
ESP_RETURN_ON_FALSE(handle_out, ESP_ERR_INVALID_ARG, TAG, "invalid handle pointer");
|
|
||||||
|
|
||||||
esp_err_t ret = ESP_OK;
|
|
||||||
|
|
||||||
struct onewire_bus_t *handle = calloc(1, sizeof(struct onewire_bus_t));
|
|
||||||
ESP_GOTO_ON_FALSE(handle, ESP_ERR_NO_MEM, err, TAG, "memory allocation for 1-wire bus handler failed");
|
|
||||||
|
|
||||||
// create rmt bytes encoder to transmit 1-wire commands and data
|
|
||||||
rmt_bytes_encoder_config_t bytes_encoder_config = {
|
|
||||||
.bit0 = onewire_bit0_symbol,
|
|
||||||
.bit1 = onewire_bit1_symbol,
|
|
||||||
.flags.msb_first = 0
|
|
||||||
};
|
|
||||||
ESP_GOTO_ON_ERROR(rmt_new_bytes_encoder(&bytes_encoder_config, &handle->tx_bytes_encoder),
|
|
||||||
err, TAG, "create data tx encoder failed");
|
|
||||||
|
|
||||||
// create rmt copy encoder to transmit 1-wire reset pulse or bits
|
|
||||||
rmt_copy_encoder_config_t copy_encoder_config = {};
|
|
||||||
ESP_GOTO_ON_ERROR(rmt_new_copy_encoder(©_encoder_config, &handle->tx_copy_encoder),
|
|
||||||
err, TAG, "create reset pulse tx encoder failed");
|
|
||||||
|
|
||||||
// create rmt rx channel
|
|
||||||
rmt_rx_channel_config_t onewire_rx_channel_cfg = {
|
|
||||||
.clk_src = RMT_CLK_SRC_DEFAULT,
|
|
||||||
.gpio_num = config->gpio_pin,
|
|
||||||
#if SOC_RMT_SUPPORT_RX_PINGPONG
|
|
||||||
.mem_block_symbols = 64, // when the chip is ping-pong capable, we can use less rx memory blocks
|
|
||||||
#else
|
|
||||||
.mem_block_symbols = config->max_rx_bytes * 8,
|
|
||||||
#endif
|
|
||||||
.resolution_hz = ONEWIRE_RMT_RESOLUTION_HZ, // in us
|
|
||||||
};
|
|
||||||
ESP_GOTO_ON_ERROR(rmt_new_rx_channel(&onewire_rx_channel_cfg, &handle->rx_channel),
|
|
||||||
err, TAG, "create rmt rx channel failed");
|
|
||||||
ESP_LOGI(TAG, "RMT Tx channel created for 1-wire bus");
|
|
||||||
|
|
||||||
// create rmt tx channel after rx channel
|
|
||||||
rmt_tx_channel_config_t onewire_tx_channel_cfg = {
|
|
||||||
.clk_src = RMT_CLK_SRC_DEFAULT,
|
|
||||||
.gpio_num = config->gpio_pin,
|
|
||||||
.mem_block_symbols = 64, // ping-pong is always avaliable on tx channel, save hardware memory blocks
|
|
||||||
.resolution_hz = ONEWIRE_RMT_RESOLUTION_HZ, // in us
|
|
||||||
.trans_queue_depth = 4,
|
|
||||||
.flags.io_loop_back = true, // make tx channel coexist with rx channel on the same gpio pin
|
|
||||||
.flags.io_od_mode = true // enable open-drain mode for 1-wire bus
|
|
||||||
};
|
|
||||||
ESP_GOTO_ON_ERROR(rmt_new_tx_channel(&onewire_tx_channel_cfg, &handle->tx_channel),
|
|
||||||
err, TAG, "create rmt tx channel failed");
|
|
||||||
ESP_LOGI(TAG, "RMT Rx channel created for 1-wire bus");
|
|
||||||
|
|
||||||
// allocate rmt rx symbol buffer
|
|
||||||
handle->rx_symbols = malloc(config->max_rx_bytes * sizeof(rmt_symbol_word_t) * 8);
|
|
||||||
ESP_GOTO_ON_FALSE(handle->rx_symbols, ESP_ERR_NO_MEM, err, TAG, "memory allocation for rx symbol buffer failed");
|
|
||||||
handle->max_rx_bytes = config->max_rx_bytes;
|
|
||||||
|
|
||||||
handle->receive_queue = xQueueCreate(1, sizeof(rmt_rx_done_event_data_t));
|
|
||||||
ESP_GOTO_ON_FALSE(handle->receive_queue, ESP_ERR_NO_MEM, err, TAG, "receive queue creation failed");
|
|
||||||
|
|
||||||
// register rmt rx done callback
|
|
||||||
rmt_rx_event_callbacks_t cbs = {
|
|
||||||
.on_recv_done = onewire_rmt_rx_done_callback
|
|
||||||
};
|
|
||||||
ESP_GOTO_ON_ERROR(rmt_rx_register_event_callbacks(handle->rx_channel, &cbs, handle),
|
|
||||||
err, TAG, "enable rmt rx channel failed");
|
|
||||||
|
|
||||||
// enable rmt channels
|
|
||||||
ESP_GOTO_ON_ERROR(rmt_enable(handle->rx_channel), err, TAG, "enable rmt rx channel failed");
|
|
||||||
ESP_GOTO_ON_ERROR(rmt_enable(handle->tx_channel), err, TAG, "enable rmt tx channel failed");
|
|
||||||
|
|
||||||
*handle_out = handle;
|
|
||||||
return ESP_OK;
|
|
||||||
|
|
||||||
err:
|
|
||||||
if (handle) {
|
|
||||||
onewire_del_bus(handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t onewire_del_bus(onewire_bus_handle_t handle)
|
|
||||||
{
|
|
||||||
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid 1-wire handle");
|
|
||||||
|
|
||||||
if (handle->tx_bytes_encoder) {
|
|
||||||
rmt_del_encoder(handle->tx_bytes_encoder);
|
|
||||||
}
|
|
||||||
if (handle->tx_copy_encoder) {
|
|
||||||
rmt_del_encoder(handle->tx_copy_encoder);
|
|
||||||
}
|
|
||||||
if (handle->rx_channel) {
|
|
||||||
rmt_disable(handle->rx_channel);
|
|
||||||
rmt_del_channel(handle->rx_channel);
|
|
||||||
}
|
|
||||||
if (handle->tx_channel) {
|
|
||||||
rmt_disable(handle->tx_channel);
|
|
||||||
rmt_del_channel(handle->tx_channel);
|
|
||||||
}
|
|
||||||
if (handle->receive_queue) {
|
|
||||||
vQueueDelete(handle->receive_queue);
|
|
||||||
}
|
|
||||||
if (handle->rx_symbols) {
|
|
||||||
free(handle->rx_symbols);
|
|
||||||
}
|
|
||||||
free(handle);
|
|
||||||
|
|
||||||
return ESP_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t onewire_bus_reset(onewire_bus_handle_t handle)
|
|
||||||
{
|
|
||||||
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid 1-wire handle");
|
|
||||||
|
|
||||||
// send reset pulse while receive presence pulse
|
|
||||||
ESP_RETURN_ON_ERROR(rmt_receive(handle->rx_channel, handle->rx_symbols, sizeof(rmt_symbol_word_t) * 2, &onewire_rmt_rx_config),
|
|
||||||
TAG, "1-wire reset pulse receive failed");
|
|
||||||
ESP_RETURN_ON_ERROR(rmt_transmit(handle->tx_channel, handle->tx_copy_encoder, &onewire_reset_pulse_symbol, sizeof(onewire_reset_pulse_symbol), &onewire_rmt_tx_config),
|
|
||||||
TAG, "1-wire reset pulse transmit failed");
|
|
||||||
|
|
||||||
// wait and check presence pulse
|
|
||||||
bool is_present = false;
|
|
||||||
rmt_rx_done_event_data_t rmt_rx_evt_data;
|
|
||||||
if (xQueueReceive(handle->receive_queue, &rmt_rx_evt_data, pdMS_TO_TICKS(1000)) == pdPASS) {
|
|
||||||
is_present = onewire_rmt_check_presence_pulse(rmt_rx_evt_data.received_symbols, rmt_rx_evt_data.num_symbols);
|
|
||||||
}
|
|
||||||
|
|
||||||
return is_present ? ESP_OK : ESP_ERR_NOT_FOUND;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t onewire_bus_write_bytes(onewire_bus_handle_t handle, const uint8_t *tx_data, uint8_t tx_data_size)
|
|
||||||
{
|
|
||||||
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid 1-wire handle");
|
|
||||||
ESP_RETURN_ON_FALSE(tx_data && tx_data_size != 0, ESP_ERR_INVALID_ARG, TAG, "invalid tx buffer or buffer size");
|
|
||||||
|
|
||||||
// transmit data
|
|
||||||
ESP_RETURN_ON_ERROR(rmt_transmit(handle->tx_channel, handle->tx_bytes_encoder, tx_data, tx_data_size, &onewire_rmt_tx_config),
|
|
||||||
TAG, "1-wire data transmit failed");
|
|
||||||
|
|
||||||
// wait the transmission to complete
|
|
||||||
ESP_RETURN_ON_ERROR(rmt_tx_wait_all_done(handle->tx_channel, 50), TAG, "wait for 1-wire data transmit failed");
|
|
||||||
|
|
||||||
return ESP_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t onewire_bus_read_bytes(onewire_bus_handle_t handle, uint8_t *rx_data, size_t rx_data_size)
|
|
||||||
{
|
|
||||||
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid 1-wire handle");
|
|
||||||
ESP_RETURN_ON_FALSE(rx_data && rx_data_size != 0, ESP_ERR_INVALID_ARG, TAG, "invalid rx buffer or buffer size");
|
|
||||||
ESP_RETURN_ON_FALSE(!(rx_data_size > handle->max_rx_bytes), ESP_ERR_INVALID_ARG,
|
|
||||||
TAG, "rx_data_size too large for buffer to hold");
|
|
||||||
|
|
||||||
uint8_t tx_buffer[rx_data_size];
|
|
||||||
memset(tx_buffer, 0xFF, rx_data_size); // transmit one bits to generate read clock
|
|
||||||
|
|
||||||
// transmit 1 bits while receiving
|
|
||||||
ESP_RETURN_ON_ERROR(rmt_receive(handle->rx_channel, handle->rx_symbols, rx_data_size * 8 * sizeof(rmt_symbol_word_t), &onewire_rmt_rx_config),
|
|
||||||
TAG, "1-wire data receive failed");
|
|
||||||
ESP_RETURN_ON_ERROR(rmt_transmit(handle->tx_channel, handle->tx_bytes_encoder, tx_buffer, sizeof(tx_buffer), &onewire_rmt_tx_config),
|
|
||||||
TAG, "1-wire data transmit failed");
|
|
||||||
|
|
||||||
// wait the transmission finishes and decode data
|
|
||||||
rmt_rx_done_event_data_t rmt_rx_evt_data;
|
|
||||||
if (xQueueReceive(handle->receive_queue, &rmt_rx_evt_data, pdMS_TO_TICKS(1000)) == pdPASS) {
|
|
||||||
onewire_rmt_decode_data(rmt_rx_evt_data.received_symbols, rmt_rx_evt_data.num_symbols, rx_data);
|
|
||||||
} else {
|
|
||||||
return ESP_ERR_TIMEOUT;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ESP_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t onewire_bus_write_bit(onewire_bus_handle_t handle, uint8_t tx_bit)
|
|
||||||
{
|
|
||||||
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid 1-wire handle");
|
|
||||||
|
|
||||||
const rmt_symbol_word_t *symbol_to_transmit = tx_bit ? &onewire_bit1_symbol : &onewire_bit0_symbol;
|
|
||||||
|
|
||||||
// transmit bit
|
|
||||||
ESP_RETURN_ON_ERROR(rmt_transmit(handle->tx_channel, handle->tx_copy_encoder, symbol_to_transmit, sizeof(onewire_bit1_symbol), &onewire_rmt_tx_config),
|
|
||||||
TAG, "1-wire bit transmit failed");
|
|
||||||
|
|
||||||
// wait the transmission to complete
|
|
||||||
ESP_RETURN_ON_ERROR(rmt_tx_wait_all_done(handle->tx_channel, 50), TAG, "wait for 1-wire bit transmit failed");
|
|
||||||
|
|
||||||
return ESP_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t onewire_bus_read_bit(onewire_bus_handle_t handle, uint8_t *rx_bit)
|
|
||||||
{
|
|
||||||
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid 1-wire handle");
|
|
||||||
ESP_RETURN_ON_FALSE(rx_bit, ESP_ERR_INVALID_ARG, TAG, "invalid rx_bit pointer");
|
|
||||||
|
|
||||||
// transmit 1 bit while receiving
|
|
||||||
ESP_RETURN_ON_ERROR(rmt_receive(handle->rx_channel, handle->rx_symbols, sizeof(rmt_symbol_word_t), &onewire_rmt_rx_config),
|
|
||||||
TAG, "1-wire bit receive failed");
|
|
||||||
ESP_RETURN_ON_ERROR(rmt_transmit(handle->tx_channel, handle->tx_copy_encoder, &onewire_bit1_symbol, sizeof(onewire_bit1_symbol), &onewire_rmt_tx_config),
|
|
||||||
TAG, "1-wire bit transmit failed");
|
|
||||||
|
|
||||||
// wait the transmission finishes and decode data
|
|
||||||
rmt_rx_done_event_data_t rmt_rx_evt_data;
|
|
||||||
if (xQueueReceive(handle->receive_queue, &rmt_rx_evt_data, pdMS_TO_TICKS(1000)) == pdPASS) {
|
|
||||||
uint8_t rx_buffer[1];
|
|
||||||
onewire_rmt_decode_data(rmt_rx_evt_data.received_symbols, rmt_rx_evt_data.num_symbols, rx_buffer);
|
|
||||||
*rx_bit = rx_buffer[0] & 0x01;
|
|
||||||
} else {
|
|
||||||
return ESP_ERR_TIMEOUT;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ESP_OK;
|
|
||||||
}
|
|
@ -1,106 +0,0 @@
|
|||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include "esp_err.h"
|
|
||||||
#include "driver/gpio.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 1-wire bus config
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
typedef struct {
|
|
||||||
gpio_num_t gpio_pin; /*!< gpio used for 1-wire bus */
|
|
||||||
uint8_t max_rx_bytes; /*!< should be larger than the largest possible single receive size */
|
|
||||||
} onewire_rmt_config_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Type of 1-wire bus handle
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
typedef struct onewire_bus_t *onewire_bus_handle_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Install new 1-wire bus
|
|
||||||
*
|
|
||||||
* @param[in] config 1-wire bus configurations
|
|
||||||
* @param[out] handle_out Installed new 1-wire bus' handle
|
|
||||||
* @return
|
|
||||||
* - ESP_OK 1-wire bus is installed successfully.
|
|
||||||
* - ESP_ERR_INVALID_ARG Invalid argument.
|
|
||||||
* - ESP_ERR_NO_MEM Memory allocation failed.
|
|
||||||
*/
|
|
||||||
esp_err_t onewire_new_bus_rmt(onewire_rmt_config_t *config, onewire_bus_handle_t *handle_out);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Delete existing 1-wire bus
|
|
||||||
*
|
|
||||||
* @param[in] handle 1-wire bus handle to be deleted
|
|
||||||
* @return
|
|
||||||
* - ESP_OK 1-wire bus is deleted successfully.
|
|
||||||
* - ESP_ERR_INVALID_ARG Invalid argument.
|
|
||||||
*/
|
|
||||||
esp_err_t onewire_del_bus(onewire_bus_handle_t handle);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Send reset pulse on 1-wire bus, and detect if there are devices on the bus
|
|
||||||
*
|
|
||||||
* @param[in] handle 1-wire bus handle
|
|
||||||
* @return
|
|
||||||
* - ESP_OK There are devices present on 1-wire bus.
|
|
||||||
* - ESP_ERR_NOT_FOUND There is no device present on 1-wire bus.
|
|
||||||
*/
|
|
||||||
esp_err_t onewire_bus_reset(onewire_bus_handle_t handle);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Write bytes to 1-wire bus, this is a blocking function
|
|
||||||
*
|
|
||||||
* @param[in] handle 1-wire bus handle
|
|
||||||
* @param[in] tx_data pointer to data to be sent
|
|
||||||
* @param[in] tx_data_count number of data to be sent
|
|
||||||
* @return
|
|
||||||
* - ESP_OK Write bytes to 1-wire bus successfully.
|
|
||||||
* - ESP_ERR_INVALID_ARG Invalid argument.
|
|
||||||
*/
|
|
||||||
esp_err_t onewire_bus_write_bytes(onewire_bus_handle_t handle, const uint8_t *tx_data, uint8_t tx_data_size);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Read bytes from 1-wire bus
|
|
||||||
*
|
|
||||||
* @note While receiving data, we use rmt transmit channel to send 0xFF to generate read pulse,
|
|
||||||
* at the same time, receive channel is used to record weather the bus is pulled down by device.
|
|
||||||
*
|
|
||||||
* @param[in] handle 1-wire bus handle
|
|
||||||
* @param[out] rx_data pointer to received data
|
|
||||||
* @param[in] rx_data_count number of received data
|
|
||||||
* @return
|
|
||||||
* - ESP_OK Read bytes from 1-wire bus successfully.
|
|
||||||
* - ESP_ERR_INVALID_ARG Invalid argument.
|
|
||||||
*/
|
|
||||||
esp_err_t onewire_bus_read_bytes(onewire_bus_handle_t handle, uint8_t *rx_data, size_t rx_data_size);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Write a bit to 1-wire bus, this is a blocking function
|
|
||||||
*
|
|
||||||
* @param[in] handle 1-wire bus handle
|
|
||||||
* @param[in] tx_bit bit to transmit, 0 for zero bit, other for one bit
|
|
||||||
* @return
|
|
||||||
* - ESP_OK Write bit to 1-wire bus successfully.
|
|
||||||
* - ESP_ERR_INVALID_ARG Invalid argument.
|
|
||||||
*/
|
|
||||||
esp_err_t onewire_bus_write_bit(onewire_bus_handle_t handle, uint8_t tx_bit);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Read a bit from 1-wire bus
|
|
||||||
*
|
|
||||||
* @param[in] handle 1-wire bus handle
|
|
||||||
* @param[out] rx_bit received bit, 0 for zero bit, 1 for one bit
|
|
||||||
* @return
|
|
||||||
* - ESP_OK Read bit from 1-wire bus successfully.
|
|
||||||
* - ESP_ERR_INVALID_ARG Invalid argument.
|
|
||||||
*/
|
|
||||||
esp_err_t onewire_bus_read_bit(onewire_bus_handle_t handle, uint8_t *rx_bit);
|
|
@ -1,2 +0,0 @@
|
|||||||
idf_component_register(SRCS "onewire_ds18b20_example_main.c" "ds18b20.c"
|
|
||||||
INCLUDE_DIRS ".")
|
|
@ -1,106 +0,0 @@
|
|||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
|
||||||
*/
|
|
||||||
#include <string.h>
|
|
||||||
#include "ds18b20.h"
|
|
||||||
#include "esp_check.h"
|
|
||||||
|
|
||||||
static const char *TAG = "ds18b20";
|
|
||||||
|
|
||||||
esp_err_t ds18b20_trigger_temperature_conversion(onewire_bus_handle_t handle, const uint8_t *rom_number)
|
|
||||||
{
|
|
||||||
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid 1-wire handle");
|
|
||||||
|
|
||||||
ESP_RETURN_ON_ERROR(onewire_bus_reset(handle), TAG, "error while resetting bus"); // reset bus and check if the device is present
|
|
||||||
|
|
||||||
uint8_t tx_buffer[10];
|
|
||||||
uint8_t tx_buffer_size;
|
|
||||||
|
|
||||||
if (rom_number) { // specify rom id
|
|
||||||
tx_buffer[0] = ONEWIRE_CMD_MATCH_ROM;
|
|
||||||
tx_buffer[9] = DS18B20_CMD_CONVERT_TEMP;
|
|
||||||
memcpy(&tx_buffer[1], rom_number, 8);
|
|
||||||
tx_buffer_size = 10;
|
|
||||||
} else { // skip rom id
|
|
||||||
tx_buffer[0] = ONEWIRE_CMD_SKIP_ROM;
|
|
||||||
tx_buffer[1] = DS18B20_CMD_CONVERT_TEMP;
|
|
||||||
tx_buffer_size = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
ESP_RETURN_ON_ERROR(onewire_bus_write_bytes(handle, tx_buffer, tx_buffer_size),
|
|
||||||
TAG, "error while triggering temperature convert");
|
|
||||||
|
|
||||||
return ESP_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t ds18b20_get_temperature(onewire_bus_handle_t handle, const uint8_t *rom_number, float *temperature)
|
|
||||||
{
|
|
||||||
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid 1-wire handle");
|
|
||||||
ESP_RETURN_ON_FALSE(temperature, ESP_ERR_INVALID_ARG, TAG, "invalid temperature pointer");
|
|
||||||
|
|
||||||
ESP_RETURN_ON_ERROR(onewire_bus_reset(handle), TAG, "error while resetting bus"); // reset bus and check if the device is present
|
|
||||||
|
|
||||||
ds18b20_scratchpad_t scratchpad;
|
|
||||||
|
|
||||||
uint8_t tx_buffer[10];
|
|
||||||
uint8_t tx_buffer_size;
|
|
||||||
|
|
||||||
if (rom_number) { // specify rom id
|
|
||||||
tx_buffer[0] = ONEWIRE_CMD_MATCH_ROM;
|
|
||||||
tx_buffer[9] = DS18B20_CMD_READ_SCRATCHPAD;
|
|
||||||
memcpy(&tx_buffer[1], rom_number, 8);
|
|
||||||
tx_buffer_size = 10;
|
|
||||||
} else {
|
|
||||||
tx_buffer[0] = ONEWIRE_CMD_SKIP_ROM;
|
|
||||||
tx_buffer[1] = DS18B20_CMD_READ_SCRATCHPAD;
|
|
||||||
tx_buffer_size = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
ESP_RETURN_ON_ERROR(onewire_bus_write_bytes(handle, tx_buffer, tx_buffer_size),
|
|
||||||
TAG, "error while sending read scratchpad command");
|
|
||||||
ESP_RETURN_ON_ERROR(onewire_bus_read_bytes(handle, (uint8_t *)&scratchpad, sizeof(scratchpad)),
|
|
||||||
TAG, "error while reading scratchpad command");
|
|
||||||
|
|
||||||
ESP_RETURN_ON_FALSE(onewire_check_crc8((uint8_t *)&scratchpad, 8) == scratchpad.crc_value, ESP_ERR_INVALID_CRC,
|
|
||||||
TAG, "crc error");
|
|
||||||
|
|
||||||
static const uint8_t lsb_mask[4] = { 0x07, 0x03, 0x01, 0x00 };
|
|
||||||
uint8_t lsb_masked = scratchpad.temp_lsb & (~lsb_mask[scratchpad.configuration >> 5]); // mask bits not used in low resolution
|
|
||||||
*temperature = (((int16_t)scratchpad.temp_msb << 8) | lsb_masked) / 16.0f;
|
|
||||||
|
|
||||||
return ESP_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t ds18b20_set_resolution(onewire_bus_handle_t handle, const uint8_t *rom_number, ds18b20_resolution_t resolution)
|
|
||||||
{
|
|
||||||
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid 1-wire handle");
|
|
||||||
|
|
||||||
ESP_RETURN_ON_ERROR(onewire_bus_reset(handle), TAG, "error while resetting bus"); // reset bus and check if the device is present
|
|
||||||
|
|
||||||
uint8_t tx_buffer[10];
|
|
||||||
uint8_t tx_buffer_size;
|
|
||||||
|
|
||||||
if (rom_number) { // specify rom id
|
|
||||||
tx_buffer[0] = ONEWIRE_CMD_MATCH_ROM;
|
|
||||||
tx_buffer[9] = DS18B20_CMD_WRITE_SCRATCHPAD;
|
|
||||||
memcpy(&tx_buffer[1], rom_number, 8);
|
|
||||||
tx_buffer_size = 10;
|
|
||||||
} else {
|
|
||||||
tx_buffer[0] = ONEWIRE_CMD_SKIP_ROM;
|
|
||||||
tx_buffer[1] = DS18B20_CMD_WRITE_SCRATCHPAD;
|
|
||||||
tx_buffer_size = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
ESP_RETURN_ON_ERROR(onewire_bus_write_bytes(handle, tx_buffer, tx_buffer_size),
|
|
||||||
TAG, "error while sending read scratchpad command");
|
|
||||||
|
|
||||||
tx_buffer[0] = 0;
|
|
||||||
tx_buffer[1] = 0;
|
|
||||||
tx_buffer[2] = resolution;
|
|
||||||
ESP_RETURN_ON_ERROR(onewire_bus_write_bytes(handle, tx_buffer, 3),
|
|
||||||
TAG, "error while sending write scratchpad command");
|
|
||||||
|
|
||||||
return ESP_OK;
|
|
||||||
}
|
|
@ -1,78 +0,0 @@
|
|||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
|
||||||
*/
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "onewire_bus.h"
|
|
||||||
|
|
||||||
#define DS18B20_CMD_CONVERT_TEMP 0x44
|
|
||||||
#define DS18B20_CMD_WRITE_SCRATCHPAD 0x4E
|
|
||||||
#define DS18B20_CMD_READ_SCRATCHPAD 0xBE
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Structure of DS18B20's scratchpad
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
typedef struct {
|
|
||||||
uint8_t temp_lsb; /*!< lsb of temperature */
|
|
||||||
uint8_t temp_msb; /*!< msb of temperature */
|
|
||||||
uint8_t th_user1; /*!< th register or user byte 1 */
|
|
||||||
uint8_t tl_user2; /*!< tl register or user byte 2 */
|
|
||||||
uint8_t configuration; /*!< configuration register */
|
|
||||||
uint8_t _reserved1;
|
|
||||||
uint8_t _reserved2;
|
|
||||||
uint8_t _reserved3;
|
|
||||||
uint8_t crc_value; /*!< crc value of scratchpad data */
|
|
||||||
} ds18b20_scratchpad_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Enumeration of DS18B20's resolution config
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
typedef enum {
|
|
||||||
DS18B20_RESOLUTION_12B = 0x7F, /*!< 750ms convert time */
|
|
||||||
DS18B20_RESOLUTION_11B = 0x5F, /*!< 375ms convert time */
|
|
||||||
DS18B20_RESOLUTION_10B = 0x3F, /*!< 187.5ms convert time */
|
|
||||||
DS18B20_RESOLUTION_9B = 0x1F, /*!< 93.75ms convert time */
|
|
||||||
} ds18b20_resolution_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Trigger temperature conversion of DS18B20
|
|
||||||
*
|
|
||||||
* @param[in] handle 1-wire handle with DS18B20 on
|
|
||||||
* @param[in] rom_number ROM number to specify which DS18B20 to send command, NULL to skip ROM
|
|
||||||
* @return
|
|
||||||
* - ESP_OK Trigger tempreture convertsion success.
|
|
||||||
* - ESP_ERR_INVALID_ARG Invalid argument.
|
|
||||||
* - ESP_ERR_NOT_FOUND There is no device present on 1-wire bus.
|
|
||||||
*/
|
|
||||||
esp_err_t ds18b20_trigger_temperature_conversion(onewire_bus_handle_t handle, const uint8_t *rom_number);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get temperature from DS18B20
|
|
||||||
*
|
|
||||||
* @param[in] handle 1-wire handle with DS18B20 on
|
|
||||||
* @param[in] rom_number ROM number to specify which DS18B20 to read from, NULL to skip ROM
|
|
||||||
* @param[out] temperature result from DS18B20
|
|
||||||
* @return
|
|
||||||
* - ESP_OK Get tempreture from DS18B20 success.
|
|
||||||
* - ESP_ERR_INVALID_ARG Invalid argument.
|
|
||||||
* - ESP_ERR_NOT_FOUND There is no device present on 1-wire bus.
|
|
||||||
* - ESP_ERR_INVALID_CRC CRC check failed.
|
|
||||||
*/
|
|
||||||
esp_err_t ds18b20_get_temperature(onewire_bus_handle_t handle, const uint8_t *rom_number, float *temperature);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set DS18B20's temperation conversion resolution
|
|
||||||
*
|
|
||||||
* @param[in] handle 1-wire handle with DS18B20 on
|
|
||||||
* @param[in] rom_number ROM number to specify which DS18B20 to read from, NULL to skip ROM
|
|
||||||
* @param[in] resolution resolution of DS18B20's temperation conversion
|
|
||||||
* @return
|
|
||||||
* - ESP_OK Set DS18B20 resolution success.
|
|
||||||
* - ESP_ERR_INVALID_ARG Invalid argument.
|
|
||||||
* - ESP_ERR_NOT_FOUND There is no device present on 1-wire bus.
|
|
||||||
*/
|
|
||||||
esp_err_t ds18b20_set_resolution(onewire_bus_handle_t handle, const uint8_t *rom_number, ds18b20_resolution_t resolution);
|
|
@ -1,90 +0,0 @@
|
|||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
|
||||||
*/
|
|
||||||
#include "freertos/FreeRTOS.h"
|
|
||||||
#include "freertos/task.h"
|
|
||||||
|
|
||||||
#include "esp_log.h"
|
|
||||||
#include "esp_check.h"
|
|
||||||
|
|
||||||
#include "onewire_bus.h"
|
|
||||||
#include "ds18b20.h"
|
|
||||||
|
|
||||||
static const char *TAG = "example";
|
|
||||||
|
|
||||||
#define EXAMPLE_ONEWIRE_GPIO_PIN GPIO_NUM_5
|
|
||||||
#define EXAMPLE_ONEWIRE_MAX_DEVICES 5
|
|
||||||
|
|
||||||
void app_main(void)
|
|
||||||
{
|
|
||||||
onewire_rmt_config_t config = {
|
|
||||||
.gpio_pin = EXAMPLE_ONEWIRE_GPIO_PIN,
|
|
||||||
.max_rx_bytes = 10, // 10 tx bytes(1byte ROM command + 8byte ROM number + 1byte device command)
|
|
||||||
};
|
|
||||||
|
|
||||||
// install new 1-wire bus
|
|
||||||
onewire_bus_handle_t handle;
|
|
||||||
ESP_ERROR_CHECK(onewire_new_bus_rmt(&config, &handle));
|
|
||||||
ESP_LOGI(TAG, "1-wire bus installed");
|
|
||||||
|
|
||||||
// create 1-wire rom search context
|
|
||||||
onewire_rom_search_context_handler_t context_handler;
|
|
||||||
ESP_ERROR_CHECK(onewire_rom_search_context_create(handle, &context_handler));
|
|
||||||
|
|
||||||
uint8_t device_num = 0;
|
|
||||||
uint8_t device_rom_id[EXAMPLE_ONEWIRE_MAX_DEVICES][8];
|
|
||||||
|
|
||||||
// search for devices on the bus
|
|
||||||
do {
|
|
||||||
esp_err_t search_result = onewire_rom_search(context_handler);
|
|
||||||
|
|
||||||
if (search_result == ESP_ERR_INVALID_CRC) {
|
|
||||||
continue; // continue on crc error
|
|
||||||
} else if (search_result == ESP_FAIL || search_result == ESP_ERR_NOT_FOUND) {
|
|
||||||
break; // break on finish or no device
|
|
||||||
}
|
|
||||||
|
|
||||||
ESP_ERROR_CHECK(onewire_rom_get_number(context_handler, device_rom_id[device_num]));
|
|
||||||
ESP_LOGI(TAG, "found device with rom id " ONEWIRE_ROM_ID_STR, ONEWIRE_ROM_ID(device_rom_id[device_num]));
|
|
||||||
device_num ++;
|
|
||||||
} while (device_num < EXAMPLE_ONEWIRE_MAX_DEVICES);
|
|
||||||
|
|
||||||
// delete 1-wire rom search context
|
|
||||||
ESP_ERROR_CHECK(onewire_rom_search_context_delete(context_handler));
|
|
||||||
ESP_LOGI(TAG, "%d device%s found on 1-wire bus", device_num, device_num > 1 ? "s" : "");
|
|
||||||
|
|
||||||
// convert and read temperature
|
|
||||||
while (device_num > 0) {
|
|
||||||
esp_err_t err;
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(200));
|
|
||||||
|
|
||||||
// set all sensors' temperature conversion resolution
|
|
||||||
err = ds18b20_set_resolution(handle, NULL, DS18B20_RESOLUTION_12B);
|
|
||||||
if (err != ESP_OK) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// trigger all sensors to start temperature conversion
|
|
||||||
err = ds18b20_trigger_temperature_conversion(handle, NULL); // skip rom to send command to all devices on the bus
|
|
||||||
if (err != ESP_OK) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(800)); // 12-bit resolution needs 750ms to convert
|
|
||||||
|
|
||||||
// get temperature from sensors
|
|
||||||
for (uint8_t i = 0; i < device_num; i ++) {
|
|
||||||
float temperature;
|
|
||||||
err = ds18b20_get_temperature(handle, device_rom_id[i], &temperature); // read scratchpad and get temperature
|
|
||||||
if (err != ESP_OK) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
ESP_LOGI(TAG, "temperature of device " ONEWIRE_ROM_ID_STR ": %.2fC", ONEWIRE_ROM_ID(device_rom_id[i]), temperature);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ESP_ERROR_CHECK(onewire_del_bus(handle));
|
|
||||||
ESP_LOGI(TAG, "1-wire bus deleted");
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user