Response to reset pulse
This commit is contained in:
parent
a94b0071f6
commit
38e8711732
@ -1 +1 @@
|
||||
idf_component_register(SRCS "main.c" INCLUDE_DIRS "include")
|
||||
idf_component_register(SRCS "zh_onewire_slave.c" INCLUDE_DIRS "include" REQUIRES driver esp_timer)
|
46
include/zh_onewire_slave.h
Executable file
46
include/zh_onewire_slave.h
Executable file
@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
#include "driver/rmt_tx.h"
|
||||
#include "driver/rmt_rx.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "esp_timer.h"
|
||||
|
||||
#define ZH_ONEWIRE_SLAVE_INIT_CONFIG_DEFAULT() \
|
||||
{ \
|
||||
.bus_pin = GPIO_NUM_5, \
|
||||
.task_priority = 4, \
|
||||
.stack_size = 2048}
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
typedef enum
|
||||
{
|
||||
ZH_DS1820 = 0x10 // DS1920, DS1820, DS18S20, DS18B20.
|
||||
} zh_onewire_slave_device_type_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
zh_onewire_slave_device_type_t device_type;
|
||||
uint8_t device_rom[8];
|
||||
} zh_onewire_slave_device_handler_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t bus_pin; // Onewire bus GPIO connection. @attention Must be pull-up to the VCC via 4.7K resistor.
|
||||
uint8_t task_priority; // Task priority for the onewire messages processing. @note It is not recommended to set a value less than 4.
|
||||
uint16_t stack_size; // Stack size for task for the onewire messages processing. @note The minimum size is 2048 bytes.
|
||||
} zh_onewire_slave_init_config_t;
|
||||
|
||||
esp_err_t zh_onewire_slave_init(const zh_onewire_slave_init_config_t *config);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
182
zh_onewire_slave.c
Executable file
182
zh_onewire_slave.c
Executable file
@ -0,0 +1,182 @@
|
||||
#include "zh_onewire_slave.h"
|
||||
|
||||
#define RESET_PULSE_DURATION 480 // Minimum value according to datasheet.
|
||||
#define WAITING_TIME_AFTER_RESET_PULSE 35 // Average value between possible datasheet values (15-60).
|
||||
#define PRESENCE_PULSE_DURATION 180 // Average value between possible datasheet values (60-240).
|
||||
#define TIME_SLOT_DURATION 90 // Average value between possible datasheet values (60-120).
|
||||
|
||||
static bool _rx_done_callback(rmt_channel_handle_t channel, const rmt_rx_done_event_data_t *edata, void *user_data);
|
||||
static size_t _tx_encoder_callback(const void *data, size_t data_size, size_t symbols_written, size_t symbols_free, rmt_symbol_word_t *symbols, bool *done, void *arg);
|
||||
static void _rx_processing(void *pvParameter);
|
||||
static void _gpio_interrupt_callback(void *arg);
|
||||
static void _gpio_interrupt_processing_task(void *pvParameter);
|
||||
|
||||
static const char *TAG = "zh_onewire_slave";
|
||||
|
||||
static rmt_channel_handle_t _tx_channel_handle = NULL;
|
||||
static rmt_channel_handle_t _rx_channel_handle = NULL;
|
||||
static rmt_encoder_handle_t _tx_encoder_handle = NULL;
|
||||
static rmt_symbol_word_t _rx_raw_buffer[64];
|
||||
static QueueHandle_t _receive_queue = {0};
|
||||
static QueueHandle_t _gpio_interrupt_queue = {0};
|
||||
static zh_onewire_slave_init_config_t _init_config = {0};
|
||||
static bool _is_initialized = false;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t level;
|
||||
uint64_t time;
|
||||
} _gpio_interrupt_data_t;
|
||||
|
||||
static rmt_receive_config_t _receive_config = {
|
||||
.signal_range_min_ns = 1000,
|
||||
.signal_range_max_ns = TIME_SLOT_DURATION * 1000,
|
||||
};
|
||||
|
||||
static rmt_transmit_config_t _transmit_config = {
|
||||
.loop_count = 0,
|
||||
};
|
||||
|
||||
static const rmt_symbol_word_t _presence_symbol_word = {
|
||||
.level0 = 1,
|
||||
.duration0 = PRESENCE_PULSE_DURATION,
|
||||
.level1 = 0,
|
||||
.duration1 = 0};
|
||||
|
||||
esp_err_t zh_onewire_slave_init(const zh_onewire_slave_init_config_t *config)
|
||||
{
|
||||
ESP_LOGI(TAG, "Onewire slave initialization begin.");
|
||||
if (config == NULL)
|
||||
{
|
||||
ESP_LOGE(TAG, "Onewire slave initialization fail. Invalid argument.");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
_init_config = *config;
|
||||
rmt_tx_channel_config_t tx_channel_config = {
|
||||
.clk_src = RMT_CLK_SRC_DEFAULT,
|
||||
.gpio_num = _init_config.bus_pin,
|
||||
.mem_block_symbols = 64,
|
||||
.resolution_hz = 1000000,
|
||||
.trans_queue_depth = 4,
|
||||
.flags.invert_out = true,
|
||||
.flags.with_dma = false,
|
||||
.flags.io_loop_back = true,
|
||||
.flags.io_od_mode = true,
|
||||
};
|
||||
rmt_rx_channel_config_t rx_channel_config = {
|
||||
.clk_src = RMT_CLK_SRC_DEFAULT,
|
||||
.resolution_hz = 1000000,
|
||||
.mem_block_symbols = 64,
|
||||
.gpio_num = _init_config.bus_pin,
|
||||
.flags.invert_in = false,
|
||||
.flags.with_dma = false,
|
||||
};
|
||||
if (rmt_new_rx_channel(&rx_channel_config, &_rx_channel_handle) != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "Onewire slave initialization fail. RMT driver error at line %d.", __LINE__);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
if (rmt_new_tx_channel(&tx_channel_config, &_tx_channel_handle) != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "Onewire slave initialization fail. RMT driver error at line %d.", __LINE__);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
rmt_rx_event_callbacks_t rx_event_callbacks = {
|
||||
.on_recv_done = _rx_done_callback,
|
||||
};
|
||||
if (rmt_rx_register_event_callbacks(_rx_channel_handle, &rx_event_callbacks, NULL) != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "Onewire slave initialization fail. RMT driver error at line %d.", __LINE__);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
const rmt_simple_encoder_config_t simple_encoder_config = {
|
||||
.callback = _tx_encoder_callback};
|
||||
if (rmt_new_simple_encoder(&simple_encoder_config, &_tx_encoder_handle) != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "Onewire slave initialization fail. RMT driver error at line %d.", __LINE__);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
if (rmt_enable(_rx_channel_handle) != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "Onewire slave initialization fail. RMT driver error at line %d.", __LINE__);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
if (rmt_enable(_tx_channel_handle) != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "Onewire slave initialization fail. RMT driver error at line %d.", __LINE__);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
_receive_queue = xQueueCreate(1, sizeof(rmt_rx_done_event_data_t));
|
||||
if (xTaskCreatePinnedToCore(&_rx_processing, "NULL", _init_config.stack_size, NULL, _init_config.task_priority, NULL, tskNO_AFFINITY) != pdPASS)
|
||||
{
|
||||
ESP_LOGE(TAG, "Onewire slave initialization fail. Internal error at line %d.", __LINE__);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
rmt_receive(_rx_channel_handle, _rx_raw_buffer, sizeof(_rx_raw_buffer), &_receive_config);
|
||||
gpio_config_t pin_config = {0};
|
||||
pin_config.intr_type = GPIO_INTR_ANYEDGE;
|
||||
pin_config.mode = GPIO_MODE_INPUT;
|
||||
pin_config.pin_bit_mask = (1ULL << (_init_config.bus_pin + 1));
|
||||
gpio_config(&pin_config);
|
||||
_gpio_interrupt_queue = xQueueCreate(10, sizeof(_gpio_interrupt_data_t)); // Check queue size!!!
|
||||
xTaskCreatePinnedToCore(&_gpio_interrupt_processing_task, "NULL", _init_config.stack_size, NULL, (_init_config.task_priority), NULL, 1);
|
||||
gpio_install_isr_service(0);
|
||||
gpio_isr_handler_add((_init_config.bus_pin + 1), _gpio_interrupt_callback, NULL);
|
||||
_is_initialized = true;
|
||||
ESP_LOGI(TAG, "Onewire slave initialization success.");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static bool _rx_done_callback(rmt_channel_handle_t channel, const rmt_rx_done_event_data_t *edata, void *user_data)
|
||||
{
|
||||
BaseType_t high_task_wakeup = pdFALSE;
|
||||
xQueueSendFromISR(_receive_queue, edata, &high_task_wakeup);
|
||||
return high_task_wakeup == pdTRUE;
|
||||
}
|
||||
|
||||
static size_t _tx_encoder_callback(const void *data, size_t data_size, size_t symbols_written, size_t symbols_free, rmt_symbol_word_t *symbols, bool *done, void *arg)
|
||||
{
|
||||
symbols[0] = _presence_symbol_word;
|
||||
*done = true;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _rx_processing(void *pvParameter)
|
||||
{
|
||||
rmt_rx_done_event_data_t rx_data = {0};
|
||||
while (xQueueReceive(_receive_queue, &rx_data, portMAX_DELAY) == pdTRUE)
|
||||
{
|
||||
rmt_receive(_rx_channel_handle, _rx_raw_buffer, sizeof(_rx_raw_buffer), &_receive_config);
|
||||
}
|
||||
}
|
||||
|
||||
void _gpio_interrupt_callback(void *arg)
|
||||
{
|
||||
_gpio_interrupt_data_t data = {0};
|
||||
data.level = gpio_get_level((_init_config.bus_pin + 1));
|
||||
data.time = esp_timer_get_time();
|
||||
xQueueSendFromISR(_gpio_interrupt_queue, &data, NULL);
|
||||
}
|
||||
|
||||
void _gpio_interrupt_processing_task(void *pvParameter)
|
||||
{
|
||||
_gpio_interrupt_data_t data = {0};
|
||||
uint64_t last_time = esp_timer_get_time();
|
||||
while (xQueueReceive(_gpio_interrupt_queue, &data, portMAX_DELAY) == pdTRUE)
|
||||
{
|
||||
if (data.level == 0)
|
||||
{
|
||||
last_time = data.time;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((data.time - last_time) > (RESET_PULSE_DURATION * 0.9) && (data.time - last_time) < (RESET_PULSE_DURATION * 2))
|
||||
{
|
||||
uint8_t pulse[1] = {1};
|
||||
rmt_transmit(_tx_channel_handle, _tx_encoder_handle, pulse, sizeof(pulse), &_transmit_config);
|
||||
rmt_tx_wait_all_done(_tx_channel_handle, portMAX_DELAY);
|
||||
}
|
||||
}
|
||||
}
|
||||
vTaskDelete(NULL);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user