1
This commit is contained in:
parent
8b8ef15dd9
commit
394a9cbd2b
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@ -42,7 +42,7 @@
|
||||
"esp_heap_caps.h": "c",
|
||||
"zh_vector.h": "c"
|
||||
},
|
||||
"idf.adapterTargetName": "esp32",
|
||||
"idf.adapterTargetName": "esp8266",
|
||||
"idf.port": "/dev/cu.usbserial-0001",
|
||||
"idf.flashType": "UART",
|
||||
"idf.openOcdConfigs": [
|
||||
|
BIN
components/espressif_ds18b20/.DS_Store
vendored
Normal file
BIN
components/espressif_ds18b20/.DS_Store
vendored
Normal file
Binary file not shown.
7
components/espressif_ds18b20/CHANGELOG.md
Normal file
7
components/espressif_ds18b20/CHANGELOG.md
Normal file
@ -0,0 +1,7 @@
|
||||
## 0.1.1
|
||||
|
||||
- Fix the issue that sign-bit is not extended properly when doing temperature value conversion.
|
||||
|
||||
## 0.1.0
|
||||
|
||||
- Initial driver version, based on the [onewire_bus](https://components.espressif.com/components/espressif/onewire_bus) library.
|
2
components/espressif_ds18b20/CMakeLists.txt
Normal file
2
components/espressif_ds18b20/CMakeLists.txt
Normal file
@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "src/ds18b20.c"
|
||||
INCLUDE_DIRS "include")
|
202
components/espressif_ds18b20/LICENSE
Normal file
202
components/espressif_ds18b20/LICENSE
Normal file
@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
63
components/espressif_ds18b20/README.md
Normal file
63
components/espressif_ds18b20/README.md
Normal file
@ -0,0 +1,63 @@
|
||||
# DS18B20 Device Driver
|
||||
|
||||
[](https://components.espressif.com/components/espressif/ds18b20)
|
||||
|
||||
DS18B20 temperature sensor only uses a single wire to write and read data, the interface is also called the `1-Wire` bus. This component only contains the sensor driver. For 1-Wire bus setup, you need to use the [onewire_bus](https://components.espressif.com/components/espressif/onewire_bus) library to initialize and enumerate the devices.
|
||||
|
||||
## How to enumerate DS18B20 devices on the 1-Wire bus
|
||||
|
||||
```c
|
||||
#define EXAMPLE_ONEWIRE_BUS_GPIO 0
|
||||
#define EXAMPLE_ONEWIRE_MAX_DS18B20 2
|
||||
|
||||
// install 1-wire bus
|
||||
onewire_bus_handle_t bus = NULL;
|
||||
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));
|
||||
|
||||
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 = {};
|
||||
// check if the device is a DS18B20, if so, return the ds18b20 handle
|
||||
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++;
|
||||
} 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);
|
||||
|
||||
// Now you have the DS18B20 sensor handle, you can use it to read the temperature
|
||||
```
|
||||
|
||||
## Trigger a temperature conversion and then read the data
|
||||
|
||||
```c
|
||||
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);
|
||||
}
|
||||
```
|
||||
|
||||
## Reference
|
||||
|
||||
* See [DS18B20 datasheet](https://www.analog.com/media/en/technical-documentation/data-sheets/ds18b20.pdf)
|
6
components/espressif_ds18b20/idf_component.yml
Normal file
6
components/espressif_ds18b20/idf_component.yml
Normal file
@ -0,0 +1,6 @@
|
||||
dependencies:
|
||||
onewire_bus:
|
||||
version: ^1.0.0
|
||||
description: DS18B20 device driver
|
||||
url: https://github.com/espressif/esp-bsp/tree/master/components/ds18b20
|
||||
version: 0.1.1
|
97
components/espressif_ds18b20/include/ds18b20.h
Normal file
97
components/espressif_ds18b20/include/ds18b20.h
Normal file
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "onewire_device.h"
|
||||
#include "ds18b20_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Type of DS18B20 device handle
|
||||
*/
|
||||
typedef struct ds18b20_device_t *ds18b20_device_handle_t;
|
||||
|
||||
/**
|
||||
* @brief DS18B20 configuration
|
||||
*/
|
||||
typedef struct {
|
||||
} ds18b20_config_t;
|
||||
|
||||
/**
|
||||
* @brief Create a new DS18B20 device based on the general 1-Wire device
|
||||
*
|
||||
* @note The general 1-Wire device can be enumerated during the 1-Wire bus device search process,
|
||||
* this function is going to check and upgrade that into a DS18B20 device.
|
||||
*
|
||||
* @param[in] device 1-Wire device basic information, including bus handle and device ROM ID
|
||||
* @param[in] config DS18B20 configuration
|
||||
* @param[out] ret_ds18b20 Returned DS18B20 device handle
|
||||
* @return
|
||||
* - ESP_OK: Create DS18B20 device successfully
|
||||
* - ESP_ERR_INVALID_ARG: Create DS18B20 device failed due to invalid argument
|
||||
* - ESP_ERR_NO_MEM: Create DS18B20 device failed due to out of memory
|
||||
* - ESP_ERR_NOT_SUPPORTED: Create DS18B20 device failed because the device is unknown (e.g. a wrong family ID code)
|
||||
* - ESP_FAIL: Create DS18B20 device failed due to other reasons
|
||||
*/
|
||||
esp_err_t ds18b20_new_device(onewire_device_t *device, const ds18b20_config_t *config, ds18b20_device_handle_t *ret_ds18b20);
|
||||
|
||||
/**
|
||||
* @brief Delete DS18B20 device
|
||||
*
|
||||
* @param ds18b20 DS18B20 device handle returned by `ds18b20_new_device`
|
||||
* @return
|
||||
* - ESP_OK: Delete DS18B20 device successfully
|
||||
* - ESP_ERR_INVALID_ARG: Delete DS18B20 device failed due to invalid argument
|
||||
* - ESP_FAIL: Delete DS18B20 device failed due to other reasons
|
||||
*/
|
||||
esp_err_t ds18b20_del_device(ds18b20_device_handle_t ds18b20);
|
||||
|
||||
/**
|
||||
* @brief Set DS18B20's temperature conversion resolution
|
||||
*
|
||||
* @param[in] ds18b20 DS18B20 device handle returned by `ds18b20_new_device`
|
||||
* @param[in] resolution resolution of DS18B20's temperature conversion
|
||||
* @return
|
||||
* - ESP_OK: Set resolution successfully
|
||||
* - ESP_ERR_INVALID_ARG: Set resolution failed due to invalid argument
|
||||
* - ESP_FAIL: Set resolution failed due to other reasons
|
||||
*/
|
||||
esp_err_t ds18b20_set_resolution(ds18b20_device_handle_t ds18b20, ds18b20_resolution_t resolution);
|
||||
|
||||
/**
|
||||
* @brief Trigger temperature conversion of DS18B20
|
||||
*
|
||||
* @note After send the trigger command, the DS18B20 will start temperature conversion.
|
||||
* This function will delay for some while, to ensure the temperature conversion won't be interrupted.
|
||||
*
|
||||
* @param[in] ds18b20 DS18B20 device handle returned by `ds18b20_new_device`
|
||||
* @return
|
||||
* - ESP_OK: Trigger temperature conversion successfully
|
||||
* - ESP_ERR_INVALID_ARG: Trigger temperature conversion failed due to invalid argument
|
||||
* - ESP_FAIL: Trigger temperature conversion failed due to other reasons
|
||||
*/
|
||||
esp_err_t ds18b20_trigger_temperature_conversion(ds18b20_device_handle_t ds18b20);
|
||||
|
||||
/**
|
||||
* @brief Get temperature from DS18B20
|
||||
*
|
||||
* @param[in] ds18b20 DS18B20 device handle returned by `ds18b20_new_device`
|
||||
* @param[out] temperature conversion result from DS18B20
|
||||
* @return
|
||||
* - ESP_OK: Get temperature successfully
|
||||
* - ESP_ERR_INVALID_ARG: Get temperature failed due to invalid argument
|
||||
* - ESP_ERR_INVALID_CRC: Get temperature failed due to CRC check error
|
||||
* - ESP_FAIL: Get temperature failed due to other reasons
|
||||
*/
|
||||
esp_err_t ds18b20_get_temperature(ds18b20_device_handle_t ds18b20, float *temperature);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
24
components/espressif_ds18b20/include/ds18b20_types.h
Normal file
24
components/espressif_ds18b20/include/ds18b20_types.h
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief DS18B20 supported resolutions
|
||||
*/
|
||||
typedef enum {
|
||||
DS18B20_RESOLUTION_9B, /*!< 9bit, needs ~93.75ms convert time */
|
||||
DS18B20_RESOLUTION_10B, /*!< 10bit, needs ~187.5ms convert time */
|
||||
DS18B20_RESOLUTION_11B, /*!< 11bit, needs ~375ms convert time */
|
||||
DS18B20_RESOLUTION_12B, /*!< 12bit, needs ~750ms convert time */
|
||||
} ds18b20_resolution_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
143
components/espressif_ds18b20/src/ds18b20.c
Normal file
143
components/espressif_ds18b20/src/ds18b20.c
Normal file
@ -0,0 +1,143 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <string.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_check.h"
|
||||
#include "onewire_bus.h"
|
||||
#include "onewire_cmd.h"
|
||||
#include "onewire_crc.h"
|
||||
#include "ds18b20.h"
|
||||
|
||||
static const char *TAG = "ds18b20";
|
||||
|
||||
#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; /*!< resolution configuration register */
|
||||
uint8_t _reserved1;
|
||||
uint8_t _reserved2;
|
||||
uint8_t _reserved3;
|
||||
uint8_t crc_value; /*!< crc value of scratchpad data */
|
||||
} __attribute__((packed)) ds18b20_scratchpad_t;
|
||||
|
||||
typedef struct ds18b20_device_t {
|
||||
onewire_bus_handle_t bus;
|
||||
onewire_device_address_t addr;
|
||||
uint8_t th_user1;
|
||||
uint8_t tl_user2;
|
||||
ds18b20_resolution_t resolution;
|
||||
} ds18b20_device_t;
|
||||
|
||||
esp_err_t ds18b20_new_device(onewire_device_t *device, const ds18b20_config_t *config, ds18b20_device_handle_t *ret_ds18b20)
|
||||
{
|
||||
ds18b20_device_t *ds18b20 = NULL;
|
||||
ESP_RETURN_ON_FALSE(device && config && ret_ds18b20, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
// check ROM ID, the family code of DS18B20 is 0x28
|
||||
if ((device->address & 0xFF) != 0x28) {
|
||||
ESP_LOGD(TAG, "%016llX is not a DS18B20 device", device->address);
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
ds18b20 = calloc(1, sizeof(ds18b20_device_t));
|
||||
ESP_RETURN_ON_FALSE(ds18b20, ESP_ERR_NO_MEM, TAG, "no mem for ds18b20");
|
||||
ds18b20->bus = device->bus;
|
||||
ds18b20->addr = device->address;
|
||||
ds18b20->resolution = DS18B20_RESOLUTION_12B; // DS18B20 default resolution is 12 bits
|
||||
|
||||
*ret_ds18b20 = ds18b20;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t ds18b20_del_device(ds18b20_device_handle_t ds18b20)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(ds18b20, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
free(ds18b20);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t ds18b20_send_command(ds18b20_device_handle_t ds18b20, uint8_t cmd)
|
||||
{
|
||||
// send command
|
||||
uint8_t tx_buffer[10] = {0};
|
||||
tx_buffer[0] = ONEWIRE_CMD_MATCH_ROM;
|
||||
memcpy(&tx_buffer[1], &ds18b20->addr, sizeof(ds18b20->addr));
|
||||
tx_buffer[sizeof(ds18b20->addr) + 1] = cmd;
|
||||
|
||||
return onewire_bus_write_bytes(ds18b20->bus, tx_buffer, sizeof(tx_buffer));
|
||||
}
|
||||
|
||||
esp_err_t ds18b20_set_resolution(ds18b20_device_handle_t ds18b20, ds18b20_resolution_t resolution)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(ds18b20, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
// reset bus and check if the ds18b20 is present
|
||||
ESP_RETURN_ON_ERROR(onewire_bus_reset(ds18b20->bus), TAG, "reset bus error");
|
||||
|
||||
// send command: DS18B20_CMD_WRITE_SCRATCHPAD
|
||||
ESP_RETURN_ON_ERROR(ds18b20_send_command(ds18b20, DS18B20_CMD_WRITE_SCRATCHPAD), TAG, "send DS18B20_CMD_WRITE_SCRATCHPAD failed");
|
||||
|
||||
// write new resolution to scratchpad
|
||||
const uint8_t resolution_data[] = {0x1F, 0x3F, 0x5F, 0x7F};
|
||||
uint8_t tx_buffer[3] = {0};
|
||||
tx_buffer[0] = ds18b20->th_user1;
|
||||
tx_buffer[1] = ds18b20->tl_user2;
|
||||
tx_buffer[2] = resolution_data[resolution];
|
||||
ESP_RETURN_ON_ERROR(onewire_bus_write_bytes(ds18b20->bus, tx_buffer, sizeof(tx_buffer)), TAG, "send new resolution failed");
|
||||
|
||||
ds18b20->resolution = resolution;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t ds18b20_trigger_temperature_conversion(ds18b20_device_handle_t ds18b20)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(ds18b20, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
// reset bus and check if the ds18b20 is present
|
||||
ESP_RETURN_ON_ERROR(onewire_bus_reset(ds18b20->bus), TAG, "reset bus error");
|
||||
|
||||
// send command: DS18B20_CMD_CONVERT_TEMP
|
||||
ESP_RETURN_ON_ERROR(ds18b20_send_command(ds18b20, DS18B20_CMD_CONVERT_TEMP), TAG, "send DS18B20_CMD_CONVERT_TEMP failed");
|
||||
|
||||
// delay proper time for temperature conversion
|
||||
const uint32_t delays_ms[] = {100, 200, 400, 800};
|
||||
vTaskDelay(pdMS_TO_TICKS(delays_ms[ds18b20->resolution]));
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t ds18b20_get_temperature(ds18b20_device_handle_t ds18b20, float *ret_temperature)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(ds18b20 && ret_temperature, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
// reset bus and check if the ds18b20 is present
|
||||
ESP_RETURN_ON_ERROR(onewire_bus_reset(ds18b20->bus), TAG, "reset bus error");
|
||||
|
||||
// send command: DS18B20_CMD_READ_SCRATCHPAD
|
||||
ESP_RETURN_ON_ERROR(ds18b20_send_command(ds18b20, DS18B20_CMD_READ_SCRATCHPAD), TAG, "send DS18B20_CMD_READ_SCRATCHPAD failed");
|
||||
|
||||
// read scratchpad data
|
||||
ds18b20_scratchpad_t scratchpad;
|
||||
ESP_RETURN_ON_ERROR(onewire_bus_read_bytes(ds18b20->bus, (uint8_t *)&scratchpad, sizeof(scratchpad)),
|
||||
TAG, "error while reading scratchpad data");
|
||||
// check crc
|
||||
ESP_RETURN_ON_FALSE(onewire_crc8(0, (uint8_t *)&scratchpad, 8) == scratchpad.crc_value, ESP_ERR_INVALID_CRC, TAG, "scratchpad crc error");
|
||||
|
||||
const uint8_t lsb_mask[4] = {0x07, 0x03, 0x01, 0x00}; // mask bits not used in low resolution
|
||||
uint8_t lsb_masked = scratchpad.temp_lsb & (~lsb_mask[scratchpad.configuration >> 5]);
|
||||
// Combine the MSB and masked LSB into a signed 16-bit integer
|
||||
int16_t temperature_raw = (((int16_t)scratchpad.temp_msb << 8) | lsb_masked);
|
||||
// Convert the raw temperature to a float,
|
||||
*ret_temperature = temperature_raw / 16.0f;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
BIN
components/espressif_onewire_bus/.DS_Store
vendored
Normal file
BIN
components/espressif_onewire_bus/.DS_Store
vendored
Normal file
Binary file not shown.
3
components/espressif_onewire_bus/CHANGELOG.md
Normal file
3
components/espressif_onewire_bus/CHANGELOG.md
Normal file
@ -0,0 +1,3 @@
|
||||
## 1.0.0
|
||||
|
||||
- Initial driver version, with the RMT driver as backend controller
|
6
components/espressif_onewire_bus/CMakeLists.txt
Normal file
6
components/espressif_onewire_bus/CMakeLists.txt
Normal file
@ -0,0 +1,6 @@
|
||||
idf_component_register(SRCS "src/onewire_bus_api.c"
|
||||
"src/onewire_bus_impl_rmt.c"
|
||||
"src/onewire_crc.c"
|
||||
"src/onewire_device.c"
|
||||
INCLUDE_DIRS "include" "interface"
|
||||
PRIV_REQUIRES driver)
|
202
components/espressif_onewire_bus/LICENSE
Normal file
202
components/espressif_onewire_bus/LICENSE
Normal file
@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
5
components/espressif_onewire_bus/README.md
Normal file
5
components/espressif_onewire_bus/README.md
Normal file
@ -0,0 +1,5 @@
|
||||
# Dallas 1-Wire Bus Driver
|
||||
|
||||
[](https://components.espressif.com/components/espressif/onewire_bus)
|
||||
|
||||
This directory contains an implementation for Dallas 1-Wire bus by different peripherals. Currently only RMT is supported as the backend.
|
7
components/espressif_onewire_bus/idf_component.yml
Normal file
7
components/espressif_onewire_bus/idf_component.yml
Normal file
@ -0,0 +1,7 @@
|
||||
dependencies:
|
||||
idf:
|
||||
version: '>=5.0'
|
||||
description: Driver for Dalas 1-Wire bus
|
||||
issues: https://github.com/espressif/idf-extra-components/issues
|
||||
url: https://github.com/espressif/idf-extra-components/tree/master/onewire_bus
|
||||
version: 1.0.1
|
90
components/espressif_onewire_bus/include/onewire_bus.h
Normal file
90
components/espressif_onewire_bus/include/onewire_bus.h
Normal file
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "esp_err.h"
|
||||
#include "onewire_types.h"
|
||||
#include "onewire_bus_impl_rmt.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Write bytes to 1-wire bus
|
||||
*
|
||||
* @param[in] bus 1-Wire bus handle
|
||||
* @param[in] tx_data pointer to data to be sent
|
||||
* @param[in] tx_data_size size of data to be sent, in bytes
|
||||
* @return
|
||||
* - ESP_OK: Write bytes to 1-Wire bus successfully
|
||||
* - ESP_ERR_INVALID_ARG: Write bytes to 1-Wire bus failed because of invalid argument
|
||||
* - ESP_FAIL: Write bytes to 1-Wire bus failed because of other errors
|
||||
*/
|
||||
esp_err_t onewire_bus_write_bytes(onewire_bus_handle_t bus, const uint8_t *tx_data, uint8_t tx_data_size);
|
||||
|
||||
/**
|
||||
* @brief Read bytes from 1-wire bus
|
||||
*
|
||||
* @param[in] bus 1-wire bus handle
|
||||
* @param[out] rx_buf pointer to buffer to store received data
|
||||
* @param[in] rx_buf_size size of buffer to store received data, in bytes
|
||||
* @return
|
||||
* - ESP_OK: Read bytes from 1-Wire bus successfully
|
||||
* - ESP_ERR_INVALID_ARG: Read bytes from 1-Wire bus failed because of invalid argument
|
||||
* - ESP_FAIL: Read bytes from 1-Wire bus failed because of other errors
|
||||
*/
|
||||
esp_err_t onewire_bus_read_bytes(onewire_bus_handle_t bus, uint8_t *rx_buf, size_t rx_buf_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 bus, 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 bus, uint8_t *rx_bit);
|
||||
|
||||
/**
|
||||
* @brief Send reset pulse to the bus, and check if there are devices attached to the bus
|
||||
*
|
||||
* @param[in] bus 1-Wire bus handle
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: Reset 1-Wire bus successfully and find device on the bus
|
||||
* - ESP_ERR_NOT_FOUND: Reset 1-Wire bus successfully but no device found on the bus
|
||||
* - ESP_FAIL: Reset 1-Wire bus failed because of other errors
|
||||
*/
|
||||
esp_err_t onewire_bus_reset(onewire_bus_handle_t bus);
|
||||
|
||||
/**
|
||||
* @brief Free 1-Wire bus resources
|
||||
*
|
||||
* @param[in] bus 1-Wire bus handle
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: Free resources successfully
|
||||
* - ESP_FAIL: Free resources failed because error occurred
|
||||
*/
|
||||
esp_err_t onewire_bus_del(onewire_bus_handle_t bus);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "esp_err.h"
|
||||
#include "onewire_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief 1-Wire bus RMT specific configuration
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t max_rx_bytes; /*!< Set the largest possible single receive size,
|
||||
which determins the size of the internal buffer that used to save the receiving RMT symbols */
|
||||
} onewire_bus_rmt_config_t;
|
||||
|
||||
/**
|
||||
* @brief Create 1-Wire bus with RMT backend
|
||||
*
|
||||
* @note One 1-Wire bus utilizes a pair of RMT TX and RX channels
|
||||
*
|
||||
* @param[in] bus_config 1-Wire bus configuration
|
||||
* @param[in] rmt_config RMT specific configuration
|
||||
* @param[out] ret_bus Returned 1-Wire bus handle
|
||||
* @return
|
||||
* - ESP_OK: create 1-Wire bus handle successfully
|
||||
* - ESP_ERR_INVALID_ARG: create 1-Wire bus handle failed because of invalid argument
|
||||
* - ESP_ERR_NO_MEM: create 1-Wire bus handle failed because of out of memory
|
||||
* - ESP_FAIL: create 1-Wire bus handle failed because some other error
|
||||
*/
|
||||
esp_err_t onewire_new_bus_rmt(const onewire_bus_config_t *bus_config, const onewire_bus_rmt_config_t *rmt_config, onewire_bus_handle_t *ret_bus);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
12
components/espressif_onewire_bus/include/onewire_cmd.h
Normal file
12
components/espressif_onewire_bus/include/onewire_cmd.h
Normal file
@ -0,0 +1,12 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#define ONEWIRE_CMD_SEARCH_NORMAL 0xF0
|
||||
#define ONEWIRE_CMD_MATCH_ROM 0x55
|
||||
#define ONEWIRE_CMD_SKIP_ROM 0xCC
|
||||
#define ONEWIRE_CMD_SEARCH_ALARM 0xEC
|
||||
#define ONEWIRE_CMD_READ_POWER_SUPPLY 0xB4
|
27
components/espressif_onewire_bus/include/onewire_crc.h
Normal file
27
components/espressif_onewire_bus/include/onewire_crc.h
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Calculate Dallas CRC8 value of a given buffer
|
||||
*
|
||||
* @param[in] init_crc Initial CRC value
|
||||
* @param[in] input Input buffer to calculate CRC value
|
||||
* @param[in] input_size Size of input buffer, in bytes
|
||||
* @return CRC8 result of the input buffer
|
||||
*/
|
||||
uint8_t onewire_crc8(uint8_t init_crc, uint8_t *input, size_t input_size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
63
components/espressif_onewire_bus/include/onewire_device.h
Normal file
63
components/espressif_onewire_bus/include/onewire_device.h
Normal file
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "esp_err.h"
|
||||
#include "onewire_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief 1-Wire device generic type
|
||||
*/
|
||||
typedef struct onewire_device_t {
|
||||
onewire_bus_handle_t bus; /*!< Which bus the 1-Wire device is attached to */
|
||||
onewire_device_address_t address; /*!< Device address (represented by its internal ROM ID) */
|
||||
} onewire_device_t;
|
||||
|
||||
/**
|
||||
* @brief Create an iterator to enumerate the 1-Wire devices on the bus
|
||||
*
|
||||
* @param[in] bus 1-Wire bus handle
|
||||
* @param[out] ret_iter Returned created device iterator
|
||||
* @return
|
||||
* - ESP_OK: Create device iterator successfully
|
||||
* - ESP_ERR_INVALID_ARG: Invalid argument
|
||||
* - ESP_ERR_NO_MEM: No memory to create device iterator
|
||||
* - ESP_FAIL: Other errors
|
||||
*/
|
||||
esp_err_t onewire_new_device_iter(onewire_bus_handle_t bus, onewire_device_iter_handle_t *ret_iter);
|
||||
|
||||
/**
|
||||
* @brief Delete the device iterator
|
||||
*
|
||||
* @param[in] iter Device iterator handle
|
||||
* @return
|
||||
* - ESP_OK: Delete device iterator successfully
|
||||
* - ESP_ERR_INVALID_ARG: Invalid argument
|
||||
* - ESP_FAIL: Other errors
|
||||
*/
|
||||
esp_err_t onewire_del_device_iter(onewire_device_iter_handle_t iter);
|
||||
|
||||
/**
|
||||
* @brief Get the next 1-Wire device from the iterator
|
||||
*
|
||||
* @param[in] iter Device iterator handle
|
||||
* @param[out] dev Returned 1-Wire device handle
|
||||
* @return
|
||||
* - ESP_OK: Get next device successfully
|
||||
* - ESP_ERR_INVALID_ARG: Invalid argument
|
||||
* - ESP_ERR_NOT_FOUND: No more device to get
|
||||
* - ESP_FAIL: Other errors
|
||||
*/
|
||||
esp_err_t onewire_device_iter_get_next(onewire_device_iter_handle_t iter, onewire_device_t *dev);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
38
components/espressif_onewire_bus/include/onewire_types.h
Normal file
38
components/espressif_onewire_bus/include/onewire_types.h
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Type of 1-Wire bus handle
|
||||
*/
|
||||
typedef struct onewire_bus_t *onewire_bus_handle_t;
|
||||
|
||||
/**
|
||||
* @brief Type of the address for a 1-Wire compatible device
|
||||
*/
|
||||
typedef uint64_t onewire_device_address_t;
|
||||
|
||||
/**
|
||||
* @brief Type of 1-Wire device iterator handle
|
||||
*/
|
||||
typedef struct onewire_device_iter_t *onewire_device_iter_handle_t;
|
||||
|
||||
/**
|
||||
* @brief 1-Wire bus configuration
|
||||
*/
|
||||
typedef struct {
|
||||
int bus_gpio_num; /*!< GPIO number that used by the 1-Wire bus */
|
||||
} onewire_bus_config_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "esp_err.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct onewire_bus_t onewire_bus_t; /*!< Type of 1-Wire bus */
|
||||
|
||||
/**
|
||||
* @brief 1-Wire bus interface definition
|
||||
*/
|
||||
struct onewire_bus_t {
|
||||
/**
|
||||
* @brief Write bytes to 1-wire bus
|
||||
*
|
||||
* @note This is a blocking function
|
||||
*
|
||||
* @param[in] bus 1-Wire bus handle
|
||||
* @param[in] tx_data pointer to data to be sent
|
||||
* @param[in] tx_data_size size of data to be sent, in bytes
|
||||
* @return
|
||||
* - ESP_OK: Write bytes to 1-Wire bus successfully
|
||||
* - ESP_ERR_INVALID_ARG: Write bytes to 1-Wire bus failed because of invalid argument
|
||||
* - ESP_FAIL: Write bytes to 1-Wire bus failed because of other errors
|
||||
*/
|
||||
esp_err_t (*write_bytes)(onewire_bus_t *bus, const uint8_t *tx_data, uint8_t tx_data_size);
|
||||
|
||||
/**
|
||||
* @brief Read bytes from 1-wire bus
|
||||
*
|
||||
* @param[in] bus 1-wire bus handle
|
||||
* @param[out] rx_buf pointer to buffer to store received data
|
||||
* @param[in] rx_buf_size size of buffer to store received data, in bytes
|
||||
* @return
|
||||
* - ESP_OK: Read bytes from 1-Wire bus successfully
|
||||
* - ESP_ERR_INVALID_ARG: Read bytes from 1-Wire bus failed because of invalid argument
|
||||
* - ESP_FAIL: Read bytes from 1-Wire bus failed because of other errors
|
||||
*/
|
||||
esp_err_t (*read_bytes)(onewire_bus_t *bus, uint8_t *rx_buf, size_t rx_buf_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 (*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 (*read_bit)(onewire_bus_handle_t handle, uint8_t *rx_bit);
|
||||
|
||||
/**
|
||||
* @brief Send reset pulse to the bus, and check if there are devices attached to the bus
|
||||
*
|
||||
* @param[in] bus 1-Wire bus handle
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: Reset 1-Wire bus successfully and find device on the bus
|
||||
* - ESP_ERR_NOT_FOUND: Reset 1-Wire bus successfully but no device found on the bus
|
||||
* - ESP_FAIL: Reset 1-Wire bus failed because of other errors
|
||||
*/
|
||||
esp_err_t (*reset)(onewire_bus_t *bus);
|
||||
|
||||
/**
|
||||
* @brief Free 1-Wire bus resources
|
||||
*
|
||||
* @param[in] bus 1-Wire bus handle
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: Free resources successfully
|
||||
* - ESP_FAIL: Free resources failed because error occurred
|
||||
*/
|
||||
esp_err_t (*del)(onewire_bus_t *bus);
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
47
components/espressif_onewire_bus/src/onewire_bus_api.c
Normal file
47
components/espressif_onewire_bus/src/onewire_bus_api.c
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "esp_log.h"
|
||||
#include "esp_check.h"
|
||||
#include "onewire_types.h"
|
||||
#include "onewire_bus_interface.h"
|
||||
|
||||
static const char *TAG = "1-wire";
|
||||
|
||||
esp_err_t onewire_bus_reset(onewire_bus_handle_t bus)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(bus, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
return bus->reset(bus);
|
||||
}
|
||||
|
||||
esp_err_t onewire_bus_write_bytes(onewire_bus_handle_t bus, const uint8_t *tx_data, uint8_t tx_data_size)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(bus && tx_data && tx_data_size, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
return bus->write_bytes(bus, tx_data, tx_data_size);
|
||||
}
|
||||
|
||||
esp_err_t onewire_bus_read_bytes(onewire_bus_handle_t bus, uint8_t *rx_buf, size_t rx_buf_size)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(bus && rx_buf && rx_buf_size, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
return bus->read_bytes(bus, rx_buf, rx_buf_size);
|
||||
}
|
||||
|
||||
esp_err_t onewire_bus_write_bit(onewire_bus_handle_t bus, uint8_t tx_bit)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(bus, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
return bus->write_bit(bus, tx_bit);
|
||||
}
|
||||
|
||||
esp_err_t onewire_bus_read_bit(onewire_bus_handle_t bus, uint8_t *rx_bit)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(bus && rx_bit, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
return bus->read_bit(bus, rx_bit);
|
||||
}
|
||||
|
||||
esp_err_t onewire_bus_del(onewire_bus_handle_t bus)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(bus, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
return bus->del(bus);
|
||||
}
|
495
components/espressif_onewire_bus/src/onewire_bus_impl_rmt.c
Normal file
495
components/espressif_onewire_bus/src/onewire_bus_impl_rmt.c
Normal file
@ -0,0 +1,495 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2023 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 "freertos/semphr.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_attr.h"
|
||||
#include "driver/rmt_tx.h"
|
||||
#include "driver/rmt_rx.h"
|
||||
#include "onewire_bus_impl_rmt.h"
|
||||
#include "onewire_bus_interface.h"
|
||||
|
||||
static const char *TAG = "1-wire.rmt";
|
||||
|
||||
#define ONEWIRE_RMT_RESOLUTION_HZ 1000000 // RMT channel default resolution for 1-wire bus, 1MHz, 1tick = 1us
|
||||
#define ONEWIRE_RMT_DEFAULT_TRANS_QUEUE_SIZE 4
|
||||
|
||||
// the memory size of each RMT channel, in words (4 bytes)
|
||||
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
|
||||
#define ONEWIRE_RMT_DEFAULT_MEM_BLOCK_SYMBOLS 64
|
||||
#else
|
||||
#define ONEWIRE_RMT_DEFAULT_MEM_BLOCK_SYMBOLS 48
|
||||
#endif
|
||||
|
||||
// for chips whose RMT RX channel doesn't support ping-pong, we need the user to tell the maximum number of bytes will be received
|
||||
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
|
||||
// one RMT symbol represents one bit, so x8
|
||||
#define ONEWIRE_RMT_RX_MEM_BLOCK_SIZE (rmt_config->max_rx_bytes * 8)
|
||||
#else // otherwise, we just use one memory block, to save resources
|
||||
#define ONEWIRE_RMT_RX_MEM_BLOCK_SIZE ONEWIRE_RMT_DEFAULT_MEM_BLOCK_SYMBOLS
|
||||
#endif
|
||||
|
||||
/*
|
||||
Reset Pulse:
|
||||
|
||||
| RESET_PULSE | RESET_WAIT_DURATION |
|
||||
| _DURATION | |
|
||||
| | | | RESET | |
|
||||
| | * | | _PRESENCE | |
|
||||
| | | | _DURATION | |
|
||||
----------+ +-----+ +--------------
|
||||
| | | |
|
||||
| | | |
|
||||
| | | |
|
||||
+-------------+ +-----------+
|
||||
*: RESET_PRESENCE_WAIT_DURATION
|
||||
*/
|
||||
#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_PRESENCE_WAIT_DURATION_MIN 15 // minimum duration for master to wait device to show its presence
|
||||
#define ONEWIRE_RESET_PRESENCE_DURATION_MIN 60 // minimum duration for master to recognize device as present
|
||||
|
||||
/*
|
||||
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 |
|
||||
+-----------------------------+
|
||||
*/
|
||||
#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
|
||||
|
||||
typedef struct {
|
||||
onewire_bus_t base; /*!< base class */
|
||||
rmt_channel_handle_t tx_channel; /*!< rmt tx channel handler */
|
||||
rmt_channel_handle_t rx_channel; /*!< rmt rx 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_symbol_word_t *rx_symbols_buf; /*!< hold rmt raw symbols */
|
||||
|
||||
size_t max_rx_bytes; /*!< buffer size in byte for single receive transaction */
|
||||
|
||||
QueueHandle_t receive_queue;
|
||||
SemaphoreHandle_t bus_mutex;
|
||||
} onewire_bus_rmt_obj_t;
|
||||
|
||||
static rmt_symbol_word_t onewire_reset_pulse_symbol = {
|
||||
.level0 = 0,
|
||||
.duration0 = ONEWIRE_RESET_PULSE_DURATION,
|
||||
.level1 = 1,
|
||||
.duration1 = ONEWIRE_RESET_WAIT_DURATION
|
||||
};
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
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_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 esp_err_t onewire_bus_rmt_read_bit(onewire_bus_handle_t bus, uint8_t *rx_bit);
|
||||
static esp_err_t onewire_bus_rmt_write_bit(onewire_bus_handle_t bus, uint8_t tx_bit);
|
||||
static esp_err_t onewire_bus_rmt_read_bytes(onewire_bus_handle_t bus, uint8_t *rx_buf, size_t rx_buf_size);
|
||||
static esp_err_t onewire_bus_rmt_write_bytes(onewire_bus_handle_t bus, const uint8_t *tx_data, uint8_t tx_data_size);
|
||||
static esp_err_t onewire_bus_rmt_reset(onewire_bus_handle_t bus);
|
||||
static esp_err_t onewire_bus_rmt_del(onewire_bus_handle_t bus);
|
||||
static esp_err_t onewire_bus_rmt_destroy(onewire_bus_rmt_obj_t *bus_rmt);
|
||||
|
||||
IRAM_ATTR
|
||||
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;
|
||||
onewire_bus_rmt_obj_t *bus_rmt = (onewire_bus_rmt_obj_t *)user_data;
|
||||
|
||||
xQueueSendFromISR(bus_rmt->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 | | Presence |
|
||||
+------+ +-----------
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
-------------------+ +----------+
|
||||
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 | | Presence |
|
||||
------------+ +------+ +-----------
|
||||
| | | |
|
||||
| | | |
|
||||
| | | |
|
||||
+-------+ +----------+
|
||||
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)
|
||||
{
|
||||
bool ret = false;
|
||||
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_PRESENCE_WAIT_DURATION_MIN &&
|
||||
rmt_symbols[1].duration0 > ONEWIRE_RESET_PRESENCE_DURATION_MIN) {
|
||||
ret = true;
|
||||
}
|
||||
} else { // bus is low before reset pulse(first pulse after rmt channel init)
|
||||
if (rmt_symbols[0].duration0 > ONEWIRE_RESET_PRESENCE_WAIT_DURATION_MIN &&
|
||||
rmt_symbols[1].duration1 > ONEWIRE_RESET_PRESENCE_DURATION_MIN) {
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void onewire_rmt_decode_data(rmt_symbol_word_t *rmt_symbols, size_t symbol_num, uint8_t *rx_buf, size_t rx_buf_size)
|
||||
{
|
||||
size_t byte_pos = 0;
|
||||
size_t bit_pos = 0;
|
||||
for (size_t i = 0; i < symbol_num; i ++) {
|
||||
if (rmt_symbols[i].duration0 > ONEWIRE_SLOT_BIT_SAMPLE_TIME) { // 0 bit
|
||||
rx_buf[byte_pos] &= ~(1 << bit_pos); // LSB first
|
||||
} else { // 1 bit
|
||||
rx_buf[byte_pos] |= 1 << bit_pos;
|
||||
}
|
||||
bit_pos ++;
|
||||
if (bit_pos >= 8) {
|
||||
bit_pos = 0;
|
||||
byte_pos ++;
|
||||
if (byte_pos >= rx_buf_size) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t onewire_new_bus_rmt(const onewire_bus_config_t *bus_config, const onewire_bus_rmt_config_t *rmt_config, onewire_bus_handle_t *ret_bus)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
onewire_bus_rmt_obj_t *bus_rmt = NULL;
|
||||
ESP_RETURN_ON_FALSE(bus_config && rmt_config && ret_bus, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
|
||||
bus_rmt = calloc(1, sizeof(onewire_bus_rmt_obj_t));
|
||||
ESP_RETURN_ON_FALSE(bus_rmt, ESP_ERR_NO_MEM, TAG, "no mem for onewire_bus_rmt_obj_t");
|
||||
|
||||
// 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, &bus_rmt->tx_bytes_encoder),
|
||||
err, TAG, "create bytes 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, &bus_rmt->tx_copy_encoder),
|
||||
err, TAG, "create copy encoder failed");
|
||||
|
||||
// Note: must create rmt rx channel before tx channel
|
||||
rmt_rx_channel_config_t onewire_rx_channel_cfg = {
|
||||
.clk_src = RMT_CLK_SRC_DEFAULT,
|
||||
.resolution_hz = ONEWIRE_RMT_RESOLUTION_HZ,
|
||||
.gpio_num = bus_config->bus_gpio_num,
|
||||
.mem_block_symbols = ONEWIRE_RMT_RX_MEM_BLOCK_SIZE,
|
||||
};
|
||||
ESP_GOTO_ON_ERROR(rmt_new_rx_channel(&onewire_rx_channel_cfg, &bus_rmt->rx_channel),
|
||||
err, TAG, "create rmt rx channel failed");
|
||||
|
||||
// create rmt tx channel
|
||||
rmt_tx_channel_config_t onewire_tx_channel_cfg = {
|
||||
.clk_src = RMT_CLK_SRC_DEFAULT,
|
||||
.resolution_hz = ONEWIRE_RMT_RESOLUTION_HZ,
|
||||
.gpio_num = bus_config->bus_gpio_num,
|
||||
.mem_block_symbols = ONEWIRE_RMT_DEFAULT_MEM_BLOCK_SYMBOLS,
|
||||
.trans_queue_depth = ONEWIRE_RMT_DEFAULT_TRANS_QUEUE_SIZE,
|
||||
.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, &bus_rmt->tx_channel),
|
||||
err, TAG, "create rmt tx channel failed");
|
||||
|
||||
// allocate rmt rx symbol buffer, one RMT symbol represents one bit, so x8
|
||||
bus_rmt->rx_symbols_buf = malloc(rmt_config->max_rx_bytes * sizeof(rmt_symbol_word_t) * 8);
|
||||
ESP_GOTO_ON_FALSE(bus_rmt->rx_symbols_buf, ESP_ERR_NO_MEM, err, TAG, "no mem to store received RMT symbols");
|
||||
bus_rmt->max_rx_bytes = rmt_config->max_rx_bytes;
|
||||
|
||||
bus_rmt->receive_queue = xQueueCreate(1, sizeof(rmt_rx_done_event_data_t));
|
||||
ESP_GOTO_ON_FALSE(bus_rmt->receive_queue, ESP_ERR_NO_MEM, err, TAG, "receive queue creation failed");
|
||||
|
||||
bus_rmt->bus_mutex = xSemaphoreCreateMutex();
|
||||
ESP_GOTO_ON_FALSE(bus_rmt->bus_mutex, ESP_ERR_NO_MEM, err, TAG, "bus mutex 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(bus_rmt->rx_channel, &cbs, bus_rmt),
|
||||
err, TAG, "enable rmt rx channel failed");
|
||||
|
||||
// enable rmt channels
|
||||
ESP_GOTO_ON_ERROR(rmt_enable(bus_rmt->rx_channel), err, TAG, "enable rmt rx channel failed");
|
||||
ESP_GOTO_ON_ERROR(rmt_enable(bus_rmt->tx_channel), err, TAG, "enable rmt tx channel failed");
|
||||
|
||||
// release the bus by sending a special RMT symbol
|
||||
static rmt_symbol_word_t release_symbol = {
|
||||
.level0 = 1,
|
||||
.duration0 = 1,
|
||||
.level1 = 1,
|
||||
.duration1 = 0,
|
||||
};
|
||||
ESP_GOTO_ON_ERROR(rmt_transmit(bus_rmt->tx_channel, bus_rmt->tx_copy_encoder, &release_symbol,
|
||||
sizeof(release_symbol), &onewire_rmt_tx_config), err, TAG, "release bus failed");
|
||||
|
||||
bus_rmt->base.del = onewire_bus_rmt_del;
|
||||
bus_rmt->base.reset = onewire_bus_rmt_reset;
|
||||
bus_rmt->base.write_bit = onewire_bus_rmt_write_bit;
|
||||
bus_rmt->base.write_bytes = onewire_bus_rmt_write_bytes;
|
||||
bus_rmt->base.read_bit = onewire_bus_rmt_read_bit;
|
||||
bus_rmt->base.read_bytes = onewire_bus_rmt_read_bytes;
|
||||
*ret_bus = &bus_rmt->base;
|
||||
|
||||
return ret;
|
||||
|
||||
err:
|
||||
if (bus_rmt) {
|
||||
onewire_bus_rmt_destroy(bus_rmt);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t onewire_bus_rmt_destroy(onewire_bus_rmt_obj_t *bus_rmt)
|
||||
{
|
||||
if (bus_rmt->tx_bytes_encoder) {
|
||||
rmt_del_encoder(bus_rmt->tx_bytes_encoder);
|
||||
}
|
||||
if (bus_rmt->tx_copy_encoder) {
|
||||
rmt_del_encoder(bus_rmt->tx_copy_encoder);
|
||||
}
|
||||
if (bus_rmt->rx_channel) {
|
||||
rmt_disable(bus_rmt->rx_channel);
|
||||
rmt_del_channel(bus_rmt->rx_channel);
|
||||
}
|
||||
if (bus_rmt->tx_channel) {
|
||||
rmt_disable(bus_rmt->tx_channel);
|
||||
rmt_del_channel(bus_rmt->tx_channel);
|
||||
}
|
||||
if (bus_rmt->receive_queue) {
|
||||
vQueueDelete(bus_rmt->receive_queue);
|
||||
}
|
||||
if (bus_rmt->bus_mutex) {
|
||||
vSemaphoreDelete(bus_rmt->bus_mutex);
|
||||
}
|
||||
if (bus_rmt->rx_symbols_buf) {
|
||||
free(bus_rmt->rx_symbols_buf);
|
||||
}
|
||||
free(bus_rmt);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t onewire_bus_rmt_del(onewire_bus_handle_t bus)
|
||||
{
|
||||
onewire_bus_rmt_obj_t *bus_rmt = __containerof(bus, onewire_bus_rmt_obj_t, base);
|
||||
return onewire_bus_rmt_destroy(bus_rmt);
|
||||
}
|
||||
|
||||
static esp_err_t onewire_bus_rmt_reset(onewire_bus_handle_t bus)
|
||||
{
|
||||
onewire_bus_rmt_obj_t *bus_rmt = __containerof(bus, onewire_bus_rmt_obj_t, base);
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
xSemaphoreTake(bus_rmt->bus_mutex, portMAX_DELAY);
|
||||
// send reset pulse while receive presence pulse
|
||||
ESP_GOTO_ON_ERROR(rmt_receive(bus_rmt->rx_channel, bus_rmt->rx_symbols_buf, sizeof(rmt_symbol_word_t) * 2, &onewire_rmt_rx_config),
|
||||
err, TAG, "1-wire reset pulse receive failed");
|
||||
ESP_GOTO_ON_ERROR(rmt_transmit(bus_rmt->tx_channel, bus_rmt->tx_copy_encoder, &onewire_reset_pulse_symbol, sizeof(onewire_reset_pulse_symbol), &onewire_rmt_tx_config),
|
||||
err, TAG, "1-wire reset pulse transmit failed");
|
||||
|
||||
// wait and check presence pulse
|
||||
rmt_rx_done_event_data_t rmt_rx_evt_data;
|
||||
ESP_GOTO_ON_FALSE(xQueueReceive(bus_rmt->receive_queue, &rmt_rx_evt_data, pdMS_TO_TICKS(1000)) == pdPASS,
|
||||
ESP_ERR_TIMEOUT, err, TAG, "1-wire reset pulse receive timeout");
|
||||
if (onewire_rmt_check_presence_pulse(rmt_rx_evt_data.received_symbols, rmt_rx_evt_data.num_symbols) == false) {
|
||||
ret = ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
err:
|
||||
xSemaphoreGive(bus_rmt->bus_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t onewire_bus_rmt_write_bytes(onewire_bus_handle_t bus, const uint8_t *tx_data, uint8_t tx_data_size)
|
||||
{
|
||||
onewire_bus_rmt_obj_t *bus_rmt = __containerof(bus, onewire_bus_rmt_obj_t, base);
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
xSemaphoreTake(bus_rmt->bus_mutex, portMAX_DELAY);
|
||||
// transmit data with the bytes encoder
|
||||
ESP_GOTO_ON_ERROR(rmt_transmit(bus_rmt->tx_channel, bus_rmt->tx_bytes_encoder, tx_data, tx_data_size, &onewire_rmt_tx_config),
|
||||
err, TAG, "1-wire data transmit failed");
|
||||
// wait the transmission to complete
|
||||
ESP_GOTO_ON_ERROR(rmt_tx_wait_all_done(bus_rmt->tx_channel, 50), err, TAG, "wait for 1-wire data transmit failed");
|
||||
|
||||
err:
|
||||
xSemaphoreGive(bus_rmt->bus_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// 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.
|
||||
static esp_err_t onewire_bus_rmt_read_bytes(onewire_bus_handle_t bus, uint8_t *rx_buf, size_t rx_buf_size)
|
||||
{
|
||||
onewire_bus_rmt_obj_t *bus_rmt = __containerof(bus, onewire_bus_rmt_obj_t, base);
|
||||
esp_err_t ret = ESP_OK;
|
||||
ESP_RETURN_ON_FALSE(rx_buf_size <= bus_rmt->max_rx_bytes, ESP_ERR_INVALID_ARG, TAG, "rx_buf_size too large for buffer to hold");
|
||||
memset(rx_buf, 0, rx_buf_size);
|
||||
|
||||
xSemaphoreTake(bus_rmt->bus_mutex, portMAX_DELAY);
|
||||
|
||||
// transmit one bits to generate read clock
|
||||
uint8_t tx_buffer[rx_buf_size];
|
||||
memset(tx_buffer, 0xFF, rx_buf_size);
|
||||
// transmit 1 bits while receiving
|
||||
ESP_GOTO_ON_ERROR(rmt_receive(bus_rmt->rx_channel, bus_rmt->rx_symbols_buf, rx_buf_size * 8 * sizeof(rmt_symbol_word_t), &onewire_rmt_rx_config),
|
||||
err, TAG, "1-wire data receive failed");
|
||||
ESP_GOTO_ON_ERROR(rmt_transmit(bus_rmt->tx_channel, bus_rmt->tx_bytes_encoder, tx_buffer, sizeof(tx_buffer), &onewire_rmt_tx_config),
|
||||
err, TAG, "1-wire data transmit failed");
|
||||
|
||||
// wait the transmission finishes and decode data
|
||||
rmt_rx_done_event_data_t rmt_rx_evt_data;
|
||||
ESP_GOTO_ON_FALSE(xQueueReceive(bus_rmt->receive_queue, &rmt_rx_evt_data, pdMS_TO_TICKS(1000)) == pdPASS, ESP_ERR_TIMEOUT,
|
||||
err, TAG, "1-wire data receive timeout");
|
||||
onewire_rmt_decode_data(rmt_rx_evt_data.received_symbols, rmt_rx_evt_data.num_symbols, rx_buf, rx_buf_size);
|
||||
|
||||
err:
|
||||
xSemaphoreGive(bus_rmt->bus_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t onewire_bus_rmt_write_bit(onewire_bus_handle_t bus, uint8_t tx_bit)
|
||||
{
|
||||
onewire_bus_rmt_obj_t *bus_rmt = __containerof(bus, onewire_bus_rmt_obj_t, base);
|
||||
const rmt_symbol_word_t *symbol_to_transmit = tx_bit ? &onewire_bit1_symbol : &onewire_bit0_symbol;
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
xSemaphoreTake(bus_rmt->bus_mutex, portMAX_DELAY);
|
||||
|
||||
// transmit bit
|
||||
ESP_GOTO_ON_ERROR(rmt_transmit(bus_rmt->tx_channel, bus_rmt->tx_copy_encoder, symbol_to_transmit, sizeof(rmt_symbol_word_t), &onewire_rmt_tx_config),
|
||||
err, TAG, "1-wire bit transmit failed");
|
||||
// wait the transmission to complete
|
||||
ESP_GOTO_ON_ERROR(rmt_tx_wait_all_done(bus_rmt->tx_channel, 50), err, TAG, "wait for 1-wire bit transmit failed");
|
||||
|
||||
err:
|
||||
xSemaphoreGive(bus_rmt->bus_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t onewire_bus_rmt_read_bit(onewire_bus_handle_t bus, uint8_t *rx_bit)
|
||||
{
|
||||
onewire_bus_rmt_obj_t *bus_rmt = __containerof(bus, onewire_bus_rmt_obj_t, base);
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
xSemaphoreTake(bus_rmt->bus_mutex, portMAX_DELAY);
|
||||
|
||||
// transmit 1 bit while receiving
|
||||
ESP_GOTO_ON_ERROR(rmt_receive(bus_rmt->rx_channel, bus_rmt->rx_symbols_buf, sizeof(rmt_symbol_word_t), &onewire_rmt_rx_config),
|
||||
err, TAG, "1-wire bit receive failed");
|
||||
ESP_GOTO_ON_ERROR(rmt_transmit(bus_rmt->tx_channel, bus_rmt->tx_copy_encoder, &onewire_bit1_symbol, sizeof(rmt_symbol_word_t), &onewire_rmt_tx_config),
|
||||
err, TAG, "1-wire bit transmit failed");
|
||||
|
||||
// wait the transmission finishes and decode data
|
||||
rmt_rx_done_event_data_t rmt_rx_evt_data;
|
||||
ESP_GOTO_ON_FALSE(xQueueReceive(bus_rmt->receive_queue, &rmt_rx_evt_data, pdMS_TO_TICKS(1000)) == pdPASS, ESP_ERR_TIMEOUT,
|
||||
err, TAG, "1-wire bit receive timeout");
|
||||
uint8_t rx_buffer = 0;
|
||||
onewire_rmt_decode_data(rmt_rx_evt_data.received_symbols, rmt_rx_evt_data.num_symbols, &rx_buffer, sizeof(rx_buffer));
|
||||
*rx_bit = rx_buffer & 0x01;
|
||||
|
||||
err:
|
||||
xSemaphoreGive(bus_rmt->bus_mutex);
|
||||
return ret;
|
||||
}
|
60
components/espressif_onewire_bus/src/onewire_crc.c
Normal file
60
components/espressif_onewire_bus/src/onewire_crc.c
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "onewire_crc.h"
|
||||
|
||||
#define FAST_CRC 1 // define this to use the fast CRC table
|
||||
|
||||
#if FAST_CRC
|
||||
|
||||
static const uint8_t dalas_crc8_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_crc8(uint8_t init_crc, uint8_t *input, size_t input_size)
|
||||
{
|
||||
uint8_t crc = init_crc;
|
||||
for (size_t i = 0; i < input_size; i ++) {
|
||||
crc = dalas_crc8_table[crc ^ input[i]];
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
#else // FAST_CRC
|
||||
|
||||
uint8_t onewire_crc8(uint8_t init_crc, uint8_t *input, size_t input_size)
|
||||
{
|
||||
uint8_t crc = init_crc;
|
||||
for (size_t i = 0; i < input_size; i++) {
|
||||
uint8_t byte = input[i];
|
||||
for (int j = 0; j < 8; j++) {
|
||||
uint8_t x = (byte ^ crc) & 0x01;
|
||||
crc >>= 1;
|
||||
if (x != 0) {
|
||||
crc ^= 0x8C;
|
||||
}
|
||||
byte >>= 1;
|
||||
}
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
#endif // FAST_CRC
|
124
components/espressif_onewire_bus/src/onewire_device.c
Normal file
124
components/espressif_onewire_bus/src/onewire_device.c
Normal file
@ -0,0 +1,124 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include "esp_check.h"
|
||||
#include "esp_log.h"
|
||||
#include "onewire_bus.h"
|
||||
#include "onewire_device.h"
|
||||
#include "onewire_crc.h"
|
||||
#include "onewire_cmd.h"
|
||||
|
||||
static const char *TAG = "1-wire.device";
|
||||
|
||||
typedef struct onewire_device_iter_t {
|
||||
onewire_bus_handle_t bus;
|
||||
uint16_t last_discrepancy;
|
||||
bool is_last_device;
|
||||
uint8_t rom_number[sizeof(onewire_device_address_t)];
|
||||
} onewire_device_iter_t;
|
||||
|
||||
esp_err_t onewire_new_device_iter(onewire_bus_handle_t bus, onewire_device_iter_handle_t *ret_iter)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(bus && ret_iter, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
|
||||
onewire_device_iter_t *iter = calloc(1, sizeof(onewire_device_iter_t));
|
||||
ESP_RETURN_ON_FALSE(iter, ESP_ERR_NO_MEM, TAG, "no mem for device iterator");
|
||||
|
||||
iter->bus = bus;
|
||||
*ret_iter = iter;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t onewire_del_device_iter(onewire_device_iter_handle_t iter)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(iter, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
|
||||
free(iter);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
// Search algorithm inspired by https://www.analog.com/en/app-notes/1wire-search-algorithm.html
|
||||
esp_err_t onewire_device_iter_get_next(onewire_device_iter_handle_t iter, onewire_device_t *dev)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(iter && dev, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
// we don't treat iterator ending and ESP_ERR_NOT_FOUND as an error condition, so just print debug message here
|
||||
if (iter->is_last_device) {
|
||||
ESP_LOGD(TAG, "1-wire rom search finished");
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
onewire_bus_handle_t bus = iter->bus;
|
||||
esp_err_t reset_result = onewire_bus_reset(bus);
|
||||
if (reset_result == ESP_ERR_NOT_FOUND) {
|
||||
ESP_LOGW(TAG, "reset bus failed: no devices found");
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
ESP_RETURN_ON_ERROR(reset_result, TAG, "reset bus failed");
|
||||
|
||||
// send rom search command and start search algorithm
|
||||
ESP_RETURN_ON_ERROR(onewire_bus_write_bytes(bus, (uint8_t[]) {
|
||||
ONEWIRE_CMD_SEARCH_NORMAL
|
||||
}, 1), TAG, "send ONEWIRE_CMD_SEARCH_NORMAL failed");
|
||||
|
||||
uint8_t last_zero = 0;
|
||||
for (uint16_t rom_bit_index = 0; rom_bit_index < sizeof(onewire_device_address_t) * 8; 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 = 0;
|
||||
uint8_t rom_bit_complement = 0;
|
||||
ESP_RETURN_ON_ERROR(onewire_bus_read_bit(bus, &rom_bit), TAG, "read rom_bit error"); // write 1 bit to read from the bus
|
||||
ESP_RETURN_ON_ERROR(onewire_bus_read_bit(bus, &rom_bit_complement), TAG, "read rom_bit_complement error"); // read a bit and its complement
|
||||
|
||||
// No devices participating in search.
|
||||
if (rom_bit && rom_bit_complement) {
|
||||
ESP_LOGE(TAG, "no devices participating in search");
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
uint8_t search_direction;
|
||||
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 < iter->last_discrepancy) { // current id bit is before the last discrepancy bit
|
||||
search_direction = (iter->rom_number[rom_byte_index] & rom_bit_mask) ? 0x01 : 0x00; // follow previous way
|
||||
} else {
|
||||
search_direction = (rom_bit_index == iter->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 search direction
|
||||
iter->rom_number[rom_byte_index] |= rom_bit_mask;
|
||||
} else {
|
||||
iter->rom_number[rom_byte_index] &= ~rom_bit_mask;
|
||||
}
|
||||
|
||||
// set search direction
|
||||
ESP_RETURN_ON_ERROR(onewire_bus_write_bit(bus, search_direction), TAG, "write direction bit error");
|
||||
}
|
||||
|
||||
// if the search was successful
|
||||
iter->last_discrepancy = last_zero;
|
||||
if (iter->last_discrepancy == 0) { // last zero loops back to the first bit
|
||||
iter->is_last_device = true;
|
||||
}
|
||||
|
||||
// check crc
|
||||
ESP_RETURN_ON_FALSE(onewire_crc8(0, iter->rom_number, 7) == iter->rom_number[7], ESP_ERR_INVALID_CRC, TAG, "bad device crc");
|
||||
|
||||
// save the ROM number as the device address
|
||||
memcpy(&dev->address, iter->rom_number, sizeof(onewire_device_address_t));
|
||||
dev->bus = bus;
|
||||
ESP_LOGD(TAG, "new 1-Wire device found, address: %016llX", dev->address);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
BIN
components/onewire/.DS_Store
vendored
Normal file
BIN
components/onewire/.DS_Store
vendored
Normal file
Binary file not shown.
6
components/onewire/CMakeLists.txt
Normal file
6
components/onewire/CMakeLists.txt
Normal file
@ -0,0 +1,6 @@
|
||||
# The following lines of boilerplate have to be in your project's CMakeLists
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(onewire)
|
74
components/onewire/README.md
Normal file
74
components/onewire/README.md
Normal file
@ -0,0 +1,74 @@
|
||||
| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | 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
components/onewire/main/CMakeLists.txt
Normal file
2
components/onewire/main/CMakeLists.txt
Normal file
@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "onewire_example_main.c"
|
||||
INCLUDE_DIRS ".")
|
2
components/onewire/main/idf_component.yml
Normal file
2
components/onewire/main/idf_component.yml
Normal file
@ -0,0 +1,2 @@
|
||||
dependencies:
|
||||
ds18b20: "^0.1.0"
|
76
components/onewire/main/onewire_example_main.c
Normal file
76
components/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);
|
||||
}
|
||||
}
|
||||
}
|
17
components/onewire/pytest_onewire.py
Normal file
17
components/onewire/pytest_onewire.py
Normal file
@ -0,0 +1,17 @@
|
||||
# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
import pytest
|
||||
from pytest_embedded import Dut
|
||||
|
||||
|
||||
@pytest.mark.esp32
|
||||
@pytest.mark.esp32s2
|
||||
@pytest.mark.esp32s3
|
||||
@pytest.mark.esp32c3
|
||||
@pytest.mark.esp32c6
|
||||
@pytest.mark.esp32h2
|
||||
@pytest.mark.generic
|
||||
def test_onewire_example(dut: Dut) -> None:
|
||||
dut.expect_exact('example: 1-Wire bus installed on GPIO')
|
||||
dut.expect_exact('example: Device iterator created, start searching')
|
||||
dut.expect_exact('example: Searching done')
|
@ -119,11 +119,29 @@ esp_err_t zh_onewire_reset(void)
|
||||
|
||||
void zh_onewire_send_byte(uint8_t byte)
|
||||
{
|
||||
ESP_LOGI(TAG, "Onewire send byte begin.");
|
||||
for (uint8_t i = 0; i < 8; ++i)
|
||||
{
|
||||
_send_bit(byte & 1);
|
||||
byte >>= 1;
|
||||
}
|
||||
ESP_LOGI(TAG, "Onewire send byte success.");
|
||||
}
|
||||
|
||||
uint8_t zh_onewire_read_byte(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "Onewire read byte begin.");
|
||||
uint8_t byte = 0;
|
||||
for (uint8_t i = 0; i < 8; ++i)
|
||||
{
|
||||
byte >>= 1;
|
||||
if (_read_bit() != 0)
|
||||
{
|
||||
byte |= 0x80;
|
||||
}
|
||||
}
|
||||
ESP_LOGI(TAG, "Onewire read byte success.");
|
||||
return byte;
|
||||
}
|
||||
|
||||
esp_err_t zh_onewire_skip_rom(void)
|
||||
@ -287,20 +305,6 @@ uint8_t *zh_onewire_search_rom_next(void)
|
||||
return &_rom[0];
|
||||
}
|
||||
|
||||
uint8_t zh_onewire_read_byte(void)
|
||||
{
|
||||
uint8_t byte = 0;
|
||||
for (uint8_t i = 0; i < 8; ++i)
|
||||
{
|
||||
byte >>= 1;
|
||||
if (_read_bit() != 0)
|
||||
{
|
||||
byte |= 0x80;
|
||||
}
|
||||
}
|
||||
return byte;
|
||||
}
|
||||
|
||||
static uint8_t _read_bit(void)
|
||||
{
|
||||
gpio_set_direction(_pin, GPIO_MODE_OUTPUT);
|
||||
|
Loading…
x
Reference in New Issue
Block a user