-
Notifications
You must be signed in to change notification settings - Fork 48
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
Improve resolution + fix crash #32
base: master
Are you sure you want to change the base?
Conversation
Crash: ```c++ _voltage = (voltage_pulse_width > 0) ? _voltage_multiplier / voltage_pulse_width / 2 : 0; ``` Since `voltage_pulse_width` is volatile, it may be set to 0 in an interrupt handling right after it was checked for not being zero. Resolution improvement: When measuring 230V mains voltage on a Sonoff POW r1, it reported the voltage with a resolution of about 8V. Changing some types to float instead of int does improve it slightly. The actual measurement was done by measuring the "last" pulse of a measurement period due to instability of the pulse frequency right after setting it. For 222 & 230V mains this was a pulse width of roughly 970 - 1000 usec. This is also roughly the jitter of an ESP8266 when handling interrupts. The change I made was to keep track of both the measurement duration, the last pulse width and count the nr. of pulses. If the nr of pulses is low, the pulse duration is way longer than the jitter, so then we can take the last pulse width. If the nr. of pulses is high, then the outliers of the first few pulses won't matter a lot. Also "instability" does work both ways and thus evens out. Now the resolution of the measurements from the CF1 pin is way more usable and also quite accurate. Compared it with the CSE7766 used in a Sonoff POW r2 and calibrated both using a proper multimeter. Both differ in the order of 0.1V from each other and the multimeter.
Maybe also merge this pending PR: https://github.com/xoseperez/hlw8012/pull/26/files |
+1, for the float instead of int for measurements and calibration
Our floats and doubles on both 8266 and 32 are software regardless of precision option? We get rid of double funcs, but idk how noticeable the speed increase or something impactful like power consumption. In case of polling performance, you might to look at removing volatile and replacing them with memory barrier instead; we don't really run into a problem of half-read variables b/c of 32bit loads on 32bit variables |
The float/double part isn't used in the callback function, nor as volatile. The main reason for me to switch to float from double was that the extra precision isn't needed and it does add up on build size.
The version bump was more of a suggestion, just in case it was overlooked. Then it could maybe still be distinguished by users. |
Let me rephrase - you don't have to use volatile nor does it use mean operation will be in sync / atomic. In ESP case, we just end up with memw instruction. In case of 8266, kind of pointless. In case of dual-core 32, minor slowdown Suggested copy is perfectly fine btw, I just meant to comment on other possible overhead (as mentioned above for doubles) |
OK, will look into the "volatile" part a bit more. |
by the way, the "ESPEasy copy" of this code does have another change which I did not include here. |
OK, I read through your links. I know the |
'volatile' in language meant to signify two things - order of operations (aka serialization) and explicitly tell the compiler it should not optimize reads or writes. When you access global variable or member, it is already thinks of both as 'globally accessible' when reading but still may optimize your operations to reduce the number of writes. Most useful example is a code one, see the asm (gdb disassemble) differences with and without one. Xtensa implementation adds It has no relation to the section attribute and 'IRAM', both this and this->member are still in the usual RAM they always were. The practical difference is you may get not most recent data, but you still get the data loaded. It is not atomic, still, unless we lock all of the data we need beforehand or transfer it some place else and signal main code that it is available for read. |
Thanks for the explanation. |
@TD-er I spotted a possible mistake in the inversion logic. I think this: const unsigned char mode = 1 - _mode;
digitalWrite(_sel_pin, _mode);
_mode = mode; should be like this (notice const unsigned char mode = 1 - _mode;
digitalWrite(_sel_pin, mode);
_mode = mode; Infact, this is what you're doing in the ESPEasy version: const unsigned char mode = 1 - _mode;
DIRECT_pinWrite_ISR(_sel_pin, mode);
_mode = mode; (BTW thank you for this patch! It works perfectly for me.) |
Ah had to re-read your post at least 3 times before I saw the misplaced The patch I now use on a Sonoff POW (r1) version and it now is actually usable and quite consistent compared to other meters (e.g. the POW r2 next to it) |
This is a good idea. |
Right now the plugin is working quite well. |
if you measure 220V or normal power, you don't need the filtering. actually fake spurious pulses cause jitter and this is another way to further reduce the jitter. i see that unfortunately the PR was not merged? |
Crash:
Since
voltage_pulse_width
is volatile, it may be set to 0 in an interrupt handling right after it was checked for not being zero.Resolution improvement:
When measuring 230V mains voltage on a Sonoff POW r1, it reported the voltage with a resolution of about 8V. Changing some types to float instead of int does improve it slightly.
The actual measurement was done by measuring the "last" pulse of a measurement period due to instability of the pulse frequency right after setting it. For 222 & 230V mains this was a pulse width of roughly 970 - 1000 usec. This is also roughly the jitter of an ESP8266 when handling interrupts.
The change I made was to keep track of both the measurement duration, the last pulse width and count the nr. of pulses. If the nr of pulses is low, the pulse duration is way longer than the jitter, so then we can take the last pulse width. If the nr. of pulses is high, then the outliers of the first few pulses won't matter a lot. Also "instability" does work both ways and thus evens out.
Now the resolution of the measurements from the CF1 pin is way more usable and also quite accurate. Compared it with the CSE7766 used in a Sonoff POW r2 and calibrated both using a proper multimeter. Both differ in the order of 0.1V from each other and the multimeter.
A before and after:
Another change I made is to get rid of
double
variables.They're not really needed here and give quite a lot of overhead as
double
computations are done in software.