Skip to content
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

2 vs 4 byte IEEE754 floats in power meters (IDFGH-7198) #3

Closed
brainstorm opened this issue Apr 19, 2022 · 10 comments
Closed

2 vs 4 byte IEEE754 floats in power meters (IDFGH-7198) #3

brainstorm opened this issue Apr 19, 2022 · 10 comments

Comments

@brainstorm
Copy link

brainstorm commented Apr 19, 2022

Hello @alisitsyn, I've applied a slight variation of the fix you proposed in the esp32 modbus power metering thread, since __beswap_32 didn't seem to be an available symbol in the 4.4 esp-idf revision I'm using, so I went with __builtin_bswap32 instead which seems to do BE swapping too:

 // mbc_serial_master.c
@@ -401,6 +410,12 @@
         }
         // Set the type of parameter found in the table
         *type = reg_info.param_type;
+		if (((	reg_info.param_type == PARAM_TYPE_FLOAT)
+			|| (reg_info.param_type == PARAM_TYPE_U32))
+			&& (reg_info.param_size == 4)) {
+			// Fix endianess for FLOAT and U32 parameter here <<<<<<<<<<<<<<<<<<<
+				*(uint32_t*)value_ptr = __builtin_bswap32(*(uint32_t*)value_ptr);
+		}
     } else {
         ESP_LOGE(TAG, "%s: The cid(%u) not found in the data dictionary.",
                                                     __FUNCTION__, reg_info.cid);

But I'm not getting the same numbers as the LCD screen is displaying, so before fudging a bit further with the offsets, I just wanted to understand why you think that my meter as 4 byte floats when the PDF manual (shown in the esp32.com forum) states 2 bytes :-?

@github-actions github-actions bot changed the title 2 vs 4 byte IEEE754 floats in power meters 2 vs 4 byte IEEE754 floats in power meters (IDFGH-7198) Apr 19, 2022
@alisitsyn
Copy link
Collaborator

alisitsyn commented Apr 19, 2022

Hello @brainstorm,

I just wanted to understand why you think that my meter as 4 byte floats when the PDF manual (shown in the esp32.com forum) states 2 bytes

Page 13, table 1 (request to read registers starting from address 0x0017) in your manual shows the example command to read 3 float values. The float value contains 2 Modbus registers = 4 bytes of data. This also clarifies how the float is stored in the data field of the Modbus response (Page13, Table2). This should be checked with your actual device.

But I'm not getting the same numbers as the LCD screen is displaying, so before

__builtin_bswap32() - is used to reverse bytes (it's used for littel/big endian issues (from gcc)). It is a bit different.

Please try to use this macro instead:

// BigEndian 32bit swap 
//   just swap the two 16 bit registers since the two bytes in each
//   register are already swapped (BigEndian) as per modbus standard.
# define __beswap_32(x) \
    (__extension__							      \
     ({ uint32_t __bsx = (x);					      \
        ((((__bsx) >> 16) & 0xffff) | (((__bsx) & 0xffff) << 16)); }))

The alternative macro from Modbus code is flexible and you can change it (the index after src) address to change the order of the bytes for example:

// from : common/include/esp_modbus_common.h
#define _XFER_4_RD(dst, src) { \
    *(uint8_t *)(dst)++ = *(uint8_t*)(src + 2); \
    *(uint8_t *)(dst)++ = *(uint8_t*)(src + 3); \
    *(uint8_t *)(dst)++ = *(uint8_t*)(src + 0); \
    *(uint8_t *)(dst)++ = *(uint8_t*)(src + 1); \
    (src) += 4; \
}

Please for now use the original addresses of start registers from table 6.1.4 on Page 13 (the first column) in the Data Dictionary table.
There are 4 combinations of 32-bit float representation in modbus devices:
Little-Endian
Big-Endian
Big-Endian byte swap
Little-Endian byte swap
If the above-proposed macro does not work in your case (the float value set over Modbus is not showed correctly on the LCD), then try to use another representation of format (change the macro).

@alisitsyn
Copy link
Collaborator

@brainstorm,

Any update on the issue? Does the above-described solution work for you?

@brainstorm
Copy link
Author

A couple of days after your message I tried a few combinations of the macro that you outlined, but no matter how I reorder the bytes, the readout did not seem to make sense still. I'll make sure I have a stable input from a DC lab power supply and triple-check because I was using solar panels and the values where fluctuating quite a bit... the last couple of weeks it has been about moving apartments which did not help in having a stable setup, but I'll come back to this, promise, I really appreciate your input and I'll keep this ball rolling ;)

I'll continue working on branch https://github.com/brainstorm/esp-modbus-power-meter/tree/alisitsyn_suggestions_debug, I'm trimming down the example to iterate faster.

@alisitsyn
Copy link
Collaborator

Thank you for the update and take your time. I can suggest using the modbuspoll tool to investigate the device first. It allows to send test commands (prepared according to manual) to the device and get answers as well as log the functionality of the transaction. Once we get the log for the reply of the command we can understand the actual change in Modbus protocol of your device and adopt the esp-modbus implementation.

@brainstorm
Copy link
Author

brainstorm commented May 2, 2022

Thanks Alex! Is there an ESP/non-windows equivalent for that tool? Looks handy but don't have physical windows machines at reach atm.

I was actually writing a small function for that purpose within the firmware: scan all holding registers linearly, shouldn't be difficult, I reckon.

@alisitsyn
Copy link
Collaborator

There are many tools for host machine that supports Modbus. I can recommend the pymodbus small example script. There are tools for android that can be found and they are usually using the BT-serial adapter for RTU.

@alisitsyn
Copy link
Collaborator

@brainstorm, I am going to close the issue because do not have response for a long time. Please feel free to reopen issue once you have some feedback.

@SaiQmon
Copy link

SaiQmon commented Jan 2, 2023

I could participate this a bit, as a total rookie. I have very little understanding about floats/integers/hex whatsoever :D
I have couple Arduino Minis in the table but so far I've tried to understand this with Raspberry Pi + CH340 RS485-USB adapter + Node-Red. My unit should be identical, part number YG899-9SY, ordered about 2020 from Aliexpress. It's up and running with 3 phase load connected.

I can get feedback from modbus, but I just cannot figure how to format the response and/or if I'm polling the right addresses?

Node-red

Based on the Chinese manual on Docs -folder + some nice hand made remarks, "Phase 1 voltage" should be at address 23+24. If I poll them I get one array and one buffer element:

image

image

image

  • I have no idea, if there is any good in these?

Converting these to Float(le) with Buffer-Parser in Node-Red doesn't do any good either:

image

image

One thing I don't get is that why it forms two separate values from each item? If you combine two values into one 32bit float, shouldn't it be just one number?


I just found that in "Include" folder cid_tables.h -file there is different address (I think..):

{ CID_HOLD_DATA_6, STR("Volts_phase_1"), STR("V"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 0x29, 2, // HOLD_OFFSET(holding_data6), PARAM_TYPE_FLOAT, PARAM_SIZE_FLOAT, OPTS( 0, 400, .001 ), PAR_PERMS_READ },

That 0x29 refers to decimal address 41 - right? I've tried this as well, no success.

I've done this similar float-conversion with TUF2000-M Ultrasonic flowmeter with Modbus RTU and it works like a charm, combining two values into one float.

Any ideas what I'm missing here?

@SaiQmon
Copy link

SaiQmon commented Jan 3, 2023

Hi again, I figured it out!

I got a new manual, mostly in reasonable English.
YG899-9SY_manual.pdf

There we can see e.g. Phase A voltage is in address 9+10 with 4-bytes, float.

image

Some testing in Node-Red shows it's actually Big-Indian Float.

image

I don't get why I have to use length of 1 in parser? But like this it works.

image


I get a lot of CRC-errors when reading over 10 addresses at once, most likely because the RS485 fieldbus is not terminated at the moment. I will hook up some 120Ohm resistor and try it again.

image
https://www.kele.com/content/blog/2014/01/17/the-rs-485-network-terminator

@alisitsyn
Copy link
Collaborator

The support for extended data types was merged to master with commit [8480ff7]. Please take a look to updated documentation

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants