ZH_AC_DIMMER 2.0.1
Loading...
Searching...
No Matches
zh_ac_dimmer.c
1#include "zh_ac_dimmer.h"
2
3static const char *TAG = "zh_ac_dimmer";
4
5#define ZH_LOGI(msg, ...) ESP_LOGI(TAG, msg, ##__VA_ARGS__)
6#define ZH_LOGE(msg, err, ...) ESP_LOGE(TAG, "[%s:%d:%s] " msg, __FILE__, __LINE__, esp_err_to_name(err), ##__VA_ARGS__)
7
8#define ZH_ERROR_CHECK(cond, err, cleanup, msg, ...) \
9 if (!(cond)) \
10 { \
11 ZH_LOGE(msg, err, ##__VA_ARGS__); \
12 cleanup; \
13 return err; \
14 }
15
16static gptimer_handle_t _dimmer_timer = NULL;
17static gptimer_alarm_config_t _alarm_config = {0};
18
19static zh_ac_dimmer_init_config_t _init_config = {0};
20static volatile uint64_t _prev_us = 0;
21static volatile uint8_t _dimmer_value = 0;
22static volatile bool _is_dimmer_work = false;
23static bool _is_initialized = false;
24static bool _is_prev_gpio_isr_handler = false;
25
26static esp_err_t _zh_ac_dimmer_validate_config(const zh_ac_dimmer_init_config_t *config);
27static esp_err_t _zh_ac_dimmer_gpio_init(const zh_ac_dimmer_init_config_t *config);
28static esp_err_t _zh_ac_dimmer_timer_init(void);
29static void _zh_ac_dimmer_isr_handler(void *arg);
30static bool _zh_ac_dimmer_timer_on_alarm_cb(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_ctx);
31
32esp_err_t zh_ac_dimmer_init(const zh_ac_dimmer_init_config_t *config) // -V2008
33{
34 ZH_LOGI("AC dimmer initialization started.");
35 ZH_ERROR_CHECK(_is_initialized == false, ESP_ERR_INVALID_STATE, NULL, "AC dimmer initialization failed. AC dimmer is already initialized.");
36 esp_err_t err = _zh_ac_dimmer_validate_config(config);
37 ZH_ERROR_CHECK(err == ESP_OK, err, NULL, "AC dimmer initialization failed. Initial configuration check failed.");
38 err = _zh_ac_dimmer_gpio_init(config);
39 ZH_ERROR_CHECK(err == ESP_OK, err, NULL, "AC dimmer initialization failed. GPIO initialization failed.");
40 err = _zh_ac_dimmer_timer_init();
41 if (_is_prev_gpio_isr_handler == true)
42 {
43 ZH_ERROR_CHECK(err == ESP_OK, err, gpio_isr_handler_remove((gpio_num_t)config->zero_cross_gpio); gpio_reset_pin((gpio_num_t)config->triac_gpio);
44 gpio_reset_pin((gpio_num_t)config->zero_cross_gpio), "AC dimmer initialization failed. Timer initialization failed.");
45 }
46 else
47 {
48 ZH_ERROR_CHECK(err == ESP_OK, err, gpio_isr_handler_remove((gpio_num_t)config->zero_cross_gpio); gpio_uninstall_isr_service(); gpio_reset_pin((gpio_num_t)config->triac_gpio);
49 gpio_reset_pin((gpio_num_t)config->zero_cross_gpio), "AC dimmer initialization failed. Timer initialization failed.");
50 }
51 _init_config = *config;
52 _is_initialized = true;
53 ZH_LOGI("AC dimmer initialization completed successfully.");
54 return ESP_OK;
55}
56
57esp_err_t zh_ac_dimmer_deinit(void)
58{
59 ZH_LOGI("AC dimmer deinitialization started.");
60 ZH_ERROR_CHECK(_is_initialized == true, ESP_ERR_INVALID_STATE, NULL, "AC dimmer deinitialization failed. AC dimmer is not initialized.");
61 gptimer_stop(_dimmer_timer);
62 gptimer_disable(_dimmer_timer);
63 gptimer_del_timer(_dimmer_timer);
64 gpio_isr_handler_remove((gpio_num_t)_init_config.zero_cross_gpio);
65 if (_is_prev_gpio_isr_handler == false)
66 {
67 gpio_uninstall_isr_service();
68 }
69 gpio_reset_pin((gpio_num_t)_init_config.triac_gpio);
70 gpio_reset_pin((gpio_num_t)_init_config.zero_cross_gpio);
71 _is_dimmer_work = false;
72 _is_initialized = false;
73 _dimmer_timer = NULL;
74 _dimmer_value = 0;
75 _prev_us = 0;
76 ZH_LOGI("AC dimmer deinitialization completed successfully.");
77 return ESP_OK;
78}
79
80esp_err_t zh_ac_dimmer_start(void)
81{
82 ZH_LOGI("AC dimmer start begin.");
83 ZH_ERROR_CHECK(_is_initialized == true, ESP_ERR_INVALID_STATE, NULL, "AC dimmer start failed. AC dimmer is not initialized.");
84 _is_dimmer_work = true;
85 ZH_LOGI("AC dimmer start completed successfully.");
86 return ESP_OK;
87}
88
89esp_err_t zh_ac_dimmer_stop(void)
90{
91 ZH_LOGI("AC dimmer stop begin.");
92 ZH_ERROR_CHECK(_is_initialized == true, ESP_ERR_INVALID_STATE, NULL, "AC dimmer stop failed. AC dimmer is not initialized.");
93 _is_dimmer_work = false;
94 ZH_LOGI("AC dimmer stop completed successfully.");
95 return ESP_OK;
96}
97
98esp_err_t zh_ac_dimmer_set(uint8_t value)
99{
100 ZH_LOGI("AC dimmer setup begin.");
101 ZH_ERROR_CHECK(_is_initialized == true, ESP_ERR_INVALID_STATE, NULL, "AC dimmer setup failed. AC dimmer is not initialized.");
102 ZH_ERROR_CHECK(value <= 100, ESP_ERR_INVALID_ARG, NULL, "AC dimmer setup failed. Dimming value invalid.");
103 _dimmer_value = value;
104 ZH_LOGI("AC dimmer setup completed successfully.");
105 return ESP_OK;
106}
107
108esp_err_t zh_ac_dimmer_get(uint8_t *value)
109{
110 ZH_LOGI("AC dimmer getting status begin.");
111 ZH_ERROR_CHECK(value != NULL, ESP_ERR_INVALID_ARG, NULL, "AC dimmer getting status failed. Value is NULL.");
112 ZH_ERROR_CHECK(_is_initialized == true, ESP_ERR_INVALID_STATE, NULL, "AC dimmer getting status failed. AC dimmer is not initialized.");
113 *value = _dimmer_value;
114 ZH_LOGI("AC dimmer getting status completed successfully.");
115 return ESP_OK;
116}
117
118static esp_err_t _zh_ac_dimmer_validate_config(const zh_ac_dimmer_init_config_t *config)
119{
120 ZH_ERROR_CHECK(config != NULL, ESP_ERR_INVALID_ARG, NULL, "Initial config is NULL.");
121 ZH_ERROR_CHECK(config->zero_cross_gpio < GPIO_NUM_MAX, ESP_ERR_INVALID_ARG, NULL, "Zero cross GPIO invalid.");
122 ZH_ERROR_CHECK(config->triac_gpio < GPIO_NUM_MAX, ESP_ERR_INVALID_ARG, NULL, "Triac GPIO invalid.");
123 ZH_ERROR_CHECK((config->zero_cross_gpio != config->triac_gpio), ESP_ERR_INVALID_ARG, NULL, "Both GPIO is same.");
124 return ESP_OK;
125}
126
127static esp_err_t _zh_ac_dimmer_gpio_init(const zh_ac_dimmer_init_config_t *config)
128{
129 gpio_config_t triac_gpio_config = {
130 .intr_type = GPIO_INTR_DISABLE,
131 .mode = GPIO_MODE_OUTPUT,
132 .pin_bit_mask = (1ULL << config->triac_gpio),
133 .pull_down_en = GPIO_PULLDOWN_DISABLE,
134 .pull_up_en = GPIO_PULLUP_DISABLE,
135 };
136 esp_err_t err = gpio_config(&triac_gpio_config);
137 ZH_ERROR_CHECK(err == ESP_OK, err, NULL, "Triac GPIO configuration failed.");
138 gpio_set_level((gpio_num_t)config->triac_gpio, 0);
139 gpio_config_t zero_cross_gpio_config = {
140 .intr_type = GPIO_INTR_POSEDGE,
141 .mode = GPIO_MODE_INPUT,
142 .pin_bit_mask = (1ULL << config->zero_cross_gpio),
143 .pull_down_en = GPIO_PULLDOWN_ENABLE,
144 .pull_up_en = GPIO_PULLUP_DISABLE,
145 };
146 err = gpio_config(&zero_cross_gpio_config);
147 ZH_ERROR_CHECK(err == ESP_OK, err, gpio_reset_pin((gpio_num_t)config->triac_gpio), "Zero cross GPIO configuration failed.");
148 err = gpio_install_isr_service(ESP_INTR_FLAG_LOWMED);
149 ZH_ERROR_CHECK(err == ESP_OK || err == ESP_ERR_INVALID_STATE, err, gpio_reset_pin((gpio_num_t)config->triac_gpio); gpio_reset_pin((gpio_num_t)config->zero_cross_gpio),
150 "Failed install isr service.")
151 if (err == ESP_ERR_INVALID_STATE)
152 {
153 _is_prev_gpio_isr_handler = true;
154 }
155 err = gpio_isr_handler_add((gpio_num_t)config->zero_cross_gpio, _zh_ac_dimmer_isr_handler, NULL);
156 if (_is_prev_gpio_isr_handler == true)
157 {
158 ZH_ERROR_CHECK(err == ESP_OK, err, gpio_reset_pin((gpio_num_t)config->triac_gpio); gpio_reset_pin((gpio_num_t)config->zero_cross_gpio), "Failed add isr handler.");
159 }
160 else
161 {
162 ZH_ERROR_CHECK(err == ESP_OK, err, gpio_uninstall_isr_service(); gpio_reset_pin((gpio_num_t)config->triac_gpio); gpio_reset_pin((gpio_num_t)config->zero_cross_gpio),
163 "Failed add isr handler.");
164 }
165 return ESP_OK;
166}
167
168static esp_err_t _zh_ac_dimmer_timer_init(void)
169{
170 gptimer_config_t timer_config = {
171 .clk_src = GPTIMER_CLK_SRC_DEFAULT,
172 .direction = GPTIMER_COUNT_UP,
173 .resolution_hz = 1 * 1000 * 1000,
174 };
175 esp_err_t err = gptimer_new_timer(&timer_config, &_dimmer_timer);
176 ZH_ERROR_CHECK(err == ESP_OK, err, NULL, "Failed create dimmer timer.");
177 gptimer_event_callbacks_t cbs = {
178 .on_alarm = _zh_ac_dimmer_timer_on_alarm_cb,
179 };
180 err = gptimer_register_event_callbacks(_dimmer_timer, &cbs, NULL);
181 ZH_ERROR_CHECK(err == ESP_OK, err, gptimer_del_timer(_dimmer_timer), "Failed register dimmer timer event callbacks.");
182 err = gptimer_enable(_dimmer_timer);
183 ZH_ERROR_CHECK(err == ESP_OK, err, gptimer_register_event_callbacks(_dimmer_timer, NULL, NULL); gptimer_del_timer(_dimmer_timer), "Failed enable dimmer timer.");
184 return ESP_OK;
185}
186
187static void IRAM_ATTR _zh_ac_dimmer_isr_handler(void *arg)
188{
189 uint64_t _current_us = esp_timer_get_time();
190 if (_current_us - _prev_us <= (1250 * 0.9)) // 90% of zero crossing period (1250 µs) at 400 Hz.
191 {
192 return;
193 }
194 gpio_set_level((gpio_num_t)_init_config.triac_gpio, 0);
195 _prev_us = _current_us;
196 if (_is_dimmer_work == false)
197 {
198 return;
199 }
200 if (_dimmer_value != 0)
201 {
202 if (_dimmer_value == 100)
203 {
204 gpio_set_level((gpio_num_t)_init_config.triac_gpio, 1);
205 return;
206 }
207 _alarm_config.alarm_count = (uint64_t)((((1250 - 330) / 100) * (100 - _dimmer_value)) + 330); // 330 is 50% of zero crossing time (by logic analyser).
208 _alarm_config.flags.auto_reload_on_alarm = false;
209 gptimer_set_alarm_action(_dimmer_timer, &_alarm_config);
210 gptimer_start(_dimmer_timer);
211 }
212}
213
214static bool IRAM_ATTR _zh_ac_dimmer_timer_on_alarm_cb(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_ctx)
215{
216 gpio_set_level((gpio_num_t)_init_config.triac_gpio, 1);
217 gptimer_stop(_dimmer_timer);
218 gptimer_set_raw_count(_dimmer_timer, 0);
219 return false;
220}
Structure for initial initialization of AC dimmer.
esp_err_t zh_ac_dimmer_init(const zh_ac_dimmer_init_config_t *config)
Initialize AC dimmer.
esp_err_t zh_ac_dimmer_get(uint8_t *value)
Get AC dimmer dimming value.
esp_err_t zh_ac_dimmer_stop(void)
Stop AC dimmer.
esp_err_t zh_ac_dimmer_start(void)
Start AC dimmer.
esp_err_t zh_ac_dimmer_deinit(void)
Deinitialize AC dimmer.
esp_err_t zh_ac_dimmer_set(uint8_t value)
Set AC dimmer dimming value.