-
Notifications
You must be signed in to change notification settings - Fork 3.1k
ESP32: TRIAC phase-dimming module #3023
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
||
These modules come with a TRIAC whose gate is intended to be driven by a GPIO pin, isolated from mains by an optocoupler. These modules also come with a zero-crossing detector, also isolated, that raises a pin voltage when the AC mains sine wave signal crosses 0V. | ||
|
||
## Architecture of this nodemcu module |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
## Architecture of this nodemcu module | |
## Architecture of this NodeMCU module |
I'm currently compiling the firmware to start testing. 🥇 The documentation is fantastic. Thank you. What is the reason you do not allow setting the dimmer pins in |
```lua | ||
dimmer.setup(14) -- configure pin 14 as zero-crossing detector | ||
dimmer.add(22) -- TRIAC gate controlling lightbulb is connected to GPIO pin 22 | ||
dimmer.setLevel(300) -- set brightness to 300‰ (30%) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dimmer.setLevel(300) -- set brightness to 300‰ (30%) | |
dimmer.setLevel(22, 300) -- set brightness to 300‰ (30%) |
* Enable *FreeRTOS in both cores* by unselecting *"Component Config/FreeRTOS/Run FreeRTOS only on first core"*. This will allow the module to use CPU1. | ||
* Unselect *"Component Config/ESP32-specific/Also watch CPU1 tick interrupt"* | ||
* Unselect *"Component Config/ESP32-specific/Watch CPU1 idle task"* |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* Enable *FreeRTOS in both cores* by unselecting *"Component Config/FreeRTOS/Run FreeRTOS only on first core"*. This will allow the module to use CPU1. | |
* Unselect *"Component Config/ESP32-specific/Also watch CPU1 tick interrupt"* | |
* Unselect *"Component Config/ESP32-specific/Watch CPU1 idle task"* | |
* Enable FreeRTOS in both cores by **deselecting** `Component Config` > `FreeRTOS` > `Run FreeRTOS only on first core`. This will allow the module to also use CPU1 (besides CPU0). | |
* **Deselect** `Component Config` > `ESP32-specific` > `Also watch CPU1 tick interrupt` | |
* **Deselect** `Component Config` > `ESP32-specific` > `Watch CPU1 idle task` |
```lua | ||
dimmer.setup(14) -- Zero crossing detector connected to GPIO14 | ||
tmr.create():alarm(1000, tmr.ALARM_AUTO, function() | ||
print("Mains frequency is %d Hz", dimmer.mainsFrequency() / 100) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prints Mains frequency is %d Hz 49.95
here.
|
||
## dimmer.remove() | ||
|
||
Removes the given pin from the dimmer module |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it intentional that this does not set the level back to 0 i.e. the light remains on? Intuitively I was expecting it to get turned off.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. |
dev-esp32
branch rather than formaster
.docs/*
.This module implements phase-dimming for TRIAC-based mains dimmers.
How phase-dimming works
Find here a brief description on how TRIAC-based dimming works.
In essence, phase dimming implies generating a square-wave PWM signal, with the special characteristic that it must be perfectly synchronized with mains, modulating it, and thus delivering more or less effective power to the load depending on the PWM signal duty cycle.
In order to do this, a dimmer module or circuit must be used to a) detect when the mains signal crosses 0V, to use it as a synchronization point and b) modulate mains. The module must isolate mains from the microcontroller.
Some reference hardware:
These modules come with a TRIAC whose gate is intended to be driven by a GPIO pin, isolated from mains by an optocoupler. These modules also come with a zero-crossing detector, also isolated, that raises a pin voltage when the AC mains sine wave signal crosses 0V.
Architecture of this nodemcu module
The above scheme is implemented in this module by dedicating ESP32's CPU1 entirely to this purpose... Phase dimming requires very accurate timing. Configuring timer interrupts in the "busy" CPU0 does not work properly, with FreeRTOS scheduler, WiFi and so on demanding their share of the CPU at random intervals, which would make dimmed lamps flicker.
Once the dimmer module is started, by means of
dimmer.setup()
, a busy loop is launched on CPU1 that monitors zero-crossing signals from the dimmer and turns on/off the TRIAC at the appropriate time, with nanosecond precision.Required SDK
menuconfig
changesTo use this module, change the following in menuconfig (
make menuconfig
):The last two settings disable the reset watchdog for CPU1. This is necessary since CPU1 is purposefully going to be running an infinite loop.
Example
dimmer.setup()
Initializes the dimmer module. This will start a task that continuously monitors for signal zero crossing and turns on/off the different dimmed pins at the right time.
Syntax
dimmer.setup(zc_pin, [transition_speed])
Parameters
zc_pin
: GPIO pin number where the zero crossing detector is connected.dimmer.setup()
will configure this pin as input.transition_speed
: integer. Specifies a transition time or fade to be applied every time a brightness level is changed. It is defined as a per mille (‰) brightness delta per half mains cycle (10ms if 50Hz). For example, if set to 20, a light would go from zero to full brightness in 1000 / 20 * 10ms = 500msReturns
Throws errors if CPU1 task cannot be started or
zc_pin
cannot be configured as input.It will reset if core 1 CPU is not active or their watchdogs are still enabled. See "Required SDK
menuconfig
changes" above.dimmer.add()
Adds the provided pin to the dimmer module. The pin will be configured as output.
Syntax
dimmer.add(pin, [dimming_mode])
Parameters
pin
: the GPIO pin to control.dimming_mode
: Dimming mode, eitherdimmer.LEADING_EDGE
(default) ordimmer.TRAILING_EDGE
, depending on the type of load or lightbulb.Returns
dimmer.add()
will throw an error if the pin was already added or if an incorrect GPIO pin is provided.dimmer.remove()
Removes the given pin from the dimmer module
Syntax
dimmer.remove(pin)
Parameters
pin
: the GPIO pin to stop controlling.Returns
Will throw an error if the pin is not currently controlled by the module.
dimmer.setLevel()
Changes the brightness level for a dimmed pin
Syntax
dimmer.setLevel(pin, brightness)
Parameters
pin
: Pin to configurebrightness
: Integer. Per-mille (‰) brightness level or duty cycle, 0: off, 1000: fully on, or anything in between.Returns
Will throw an error if attempting to configure a pin that was not added previously.
dimmer.mainsFrequency()
Returns the last measured mains frequency, in cHz (100ths of Hz). You must call
dimmer.setup()
first. Note that at least half a mains cycle must have passed (10ms at 50Hz) afterdimmer.setup()
for this function to work!Syntax
dimmer.mainsFrequency()
Returns
Integer with the measured mains frequency, in cHz.
0
if mains is not detected.Example