King Kévin b4d386c35d | ||
---|---|---|
main | ||
pictures | ||
.gitignore | ||
CMakeLists.txt | ||
LICENSE | ||
README.md |
README.md
This project is to add a computer interface to the Aneng 623 multi-meter.
This firmware if for an ESP32-C3 Super Mini development board, but should work on any ESP32 variant. It will decode the I2C communication with the device's LCD to get the measurements.
installation
Connect the pins as follows to the LCD header (available on the bottom mother board and top LCD board):
- VLCD to GPIO1: high to enable the LCD (not enough to power MCU)
- VDD do not connect: main 3.3V, always on (even when DMM is off), but it does not provide enough power.
- PT1.4 to GPIO3: I2C SDA, for the data
- PT1.5 to GPIO4: I2C SCL, for the clock
- PT2.3 do not connect: backlight
- PT2.2 do not connect: unknown
- VDDA do not connect: 3.6V (not Vbat)
- GND to GND: ground
The GPIOs can be configured in to projects menu (see compilation). The LCD header is available on the bottom mother board and top LCD board, next to the flat flex cable. Installing it in the top case provides a good WiFi signal, and should not interfere with the measurement. But exposing the USB power is harder, and connecting to it might be inconvenient. Installing it in the bottom case allows exposing the USB port next to the charging USB port, but the WiFi signal will be weaker because a lot more copper is nearby. The RF activity could also affect the measurements (not verified).
Sadly the LDO on the main board also providing 3.3V on VDD for the LCD board does not provide enough current to also power our board. As soon as it powers on the WiFi PHY interface, the 3.3V would dip to 2.5V. This is recognisable by a blinking of the LEDs on the back of the LCD. This dip will also cause the ESP to restart. You will see the following on the log output before the reboot:
I (533) wifi_init: WiFi IRAM OP enabled
I (543) wifi_init: WiFi RX IRAM OP enabled
I (543) phy_init: phy_version 118
Reducing the CPU speed and WiFi power down to the minimum 8 x 0.25 dBM does not fix the issue.
There are 3 solutions to this issue:
- You can power the ESP using its USB port. This would also allow easily connecting it to the computer. But this also connects its digital ground to your computers (see below for risks).
- Connect the V+ battery test point on the main board to the 5V pin of the ESP board. When the DMM is off (actually the LCD), the ESP goes into deep sleep mode and only uses 100 uA. Add a Schottky in line to prevent the 5V of the ESP when connected to USB to feed back in the battery. The main ESP voltage would then only be 3.0 V when not connected over USB, but it still works.
- Replace the LDO marked U3. Don't use an AMS117-3.3 or equivalent because of their huge quiescent current of 5 mA. I only had a ME6217C33M5G at hand. Its SOT-23-5 package does not fit the SOT-89 footprint, but I made it work
The multi-meter comes with a large 1800 mAh battery. It draws around 10 mA when on, 80% of it are just for the LEDs on the LCD back. I changed the R35 and R37 100 Ohm resistors with 5.1 and 2.2 kOhm, reducing the power consumption to 5 mA.
When charging using the original USB port, the orange light next to it switches on. When powered on, the multi-meter will stop any measurements, and only show the battery level on the LCD. But when the battery is charged, the light switches to green, and the multi-meter can be used again. I'm not sure if charging makes a difference in the measurements, or grounding risk, or this is just an oversight. If you plan to use it as bench multi-meter and always leave it connected to power, you can disconnect the battery. This will prevent the battery from blowing up (e.g. keeping Li-Ion at 4.2V causes it to gas). The charger is strong enough to power the multi-meter.
The USB ground is connected to the digital ground. This is not the same as the analog ground used on the COM lead, but there are connected with a 1 Mohm resistor, which could affect the measurement (or damage your computer). If you are powering it using a floating USB power supply, there are no risks. To be extra safe, and just because I could, I added a B0505S isolation transformer.
compilation
Compile the firmware using ESP-IDF (v5.3.1):
idf.py set-target esp32c3
# config project under Aneng 623 DMM interface menu
idf.py menuconfig
idf.py build
idf.py -p /dev/ttyACM0 flash
The Aneng 623 DMM configuration entry menu provides a lot of options:
- the GPIOs used
- the interfaces provided (UART, USB, network)
- the protocol used (ASYC-II, SCPI)
interfaces
The USB interface is the most practical and stable. It also allows to power the ESP, but connects the grounds (see installation)
The UART interface is mostly intended to be connected to an infra-red and used with an opto-coupler so to provide galvanic isolation. But you could simply also use it to interface with any other MCU.
The network interface is the primary goal of this project. It allows getting the measurement remotely over WiFi, also providing galvanic isolation. Provide the WiFi credentials using the configuration menu so it can connect to you access point. While on UART and USB only one protocol can be used, over network both can be provided, just by using multiple TCP ports.
No Bluetooth interface option is provided. I just find Bluetooth a pain to use on computers, and there is no phone app for this project. While Bluetooth Low Energy has the advantage would to draw less energy from the battery, the ESP BLE is actually not that efficient. But the source code is open, so feel free to add it yourself.
protocols
The data can transmitted using the ASYC-II 16-bytes ASCII protocol also used by Metrix MX56C. It it simple, but also human readable. To view the measurements, use any serial terminal (with any baud rate, and enable new line on carriage return):
picocom --imap crcrlf /dev/ttyACM0
Using this protocol also allows to interface it with sigrok:
sigrok-cli --driver=metrix-mx56c:conn=/dev/ttyACM0 --continuous
It also allows to get the battery level and second measurement, the one on the top right of the LCD. Just enable these options in the configuration menu.
You can also connect over the network (adjust the IP and port to your setup):
nc 192.168.42.168 623
Because the output does not use line feed but only carriage return, the single line with always be updated. If you still want scrolling measurements, create a serial to TCP bridge using socat, and just use the serial terminal in another tab:
socat -d pty,raw,echo=0,link=/tmp/ttyV0 tcp:192.168.42.168:623
picocom --imap crcrlf /tmp/ttyV0
Sadly the sigrok metrix-mx56c driver only allows serial connections, and cannot use the tcp-raw conn option. Also this serial interface cannot be used by sigrok, as it does not allow virtual interfaces.
The second protocol supported is SCPI. While this protocol is kind of standardised, each instrument has its own flavor of it. This project's implementation pretends to be an Agilent 34405A and only supports the minimum amount of commands (*OPC?, *IDN?, CONF?, MEAS, READ?, ABORT). This is just enough to work and perfectly interface with sigrok using the scpi-dmm driver.
Over USB:
sigrok-cli -l 5 -d scpi-dmm:conn=/dev/ttyACM0 --get measured_quantity
sigrok-cli -l 5 -d scpi-dmm:conn=/dev/ttyACM0 --samples 1 --output-format analog
And it has the advantage over ASY-CII to also be used over the network:
sigrok-cli -l 5 -d scpi-dmm:conn=tcp-raw/192.168.42.168/5555 --samples 2 --output-format analog
other
I2C
The main board communicates with the LCD board using I2C. The LCD IC used is the AiP16C23. It's I2C slave address is 0x3E (0111110). Here is the decoded traffic from the trace I recorded using pulseview.
sigrok-cli --input-file lcd_i2c_boot.sr --protocol-decoders i2c:scl=D0:sda=D1 --protocol-decoder-annotations i2c=address-read:data-read:address-write:data-write | head -n 20
i2c-1: Write
i2c-1: Address write: 3E
i2c-1: Data write: 84
i2c-1: Data write: 03
i2c-1: Write
i2c-1: Address write: 3E
i2c-1: Data write: 82
i2c-1: Data write: 00
i2c-1: Write
i2c-1: Address write: 3E
i2c-1: Data write: 8A
i2c-1: Data write: 00
i2c-1: Write
i2c-1: Address write: 3E
i2c-1: Data write: 86
i2c-1: Data write: 00
i2c-1: Write
i2c-1: Address write: 3E
i2c-1: Data write: 80
i2c-1: Data write: 00
i2c-1: Data write: 00
i2c-1: Data write: 00
i2c-1: Data write: 00
i2c-1: Data write: 00
i2c-1: Data write: 00
i2c-1: Data write: 00
i2c-1: Data write: 00
i2c-1: Data write: 00
i2c-1: Write
i2c-1: Address write: 3E
i2c-1: Data write: 80
i2c-1: Data write: 08
i2c-1: Data write: 00
i2c-1: Data write: 00
i2c-1: Data write: 00
i2c-1: Data write: 00
i2c-1: Data write: 00
i2c-1: Data write: 00
i2c-1: Data write: 00
i2c-1: Write
The first byte is the command:
- 84: System Mode Command
- 82: Drive Mode Command
- 8A: Internal Voltage Adjustment (IVA) Setting Command
- 86: Frame Frequency Command
- 80: Display Data Input Command
The 80 command sets the display memory, controlling the segments on the LCD.
This is the data our firmware is monitoring for to decode the measurement.
EEPROM
I used the ESP-IDF I2C tool to play with the bus. I used an ESP32-C3 SuperMini and changed the config:
- SDA: GPIO3
- SCL: GPIO4
- serial output: USB
check if the LCD is on the bus:
i2c-tools> i2cdetect
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- 3e --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: 50 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
the 24C02 EEPROM is actually also on the same I2C bus. let's dump it:
i2c-tools> i2cdump -c 0x50
0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
00: ff ff ff ff ff ff ff ff ff 52 00 22 01 f0 05 04 .........R."????
10: 10 27 1f 4e 08 07 65 4c 64 4b 28 28 0a 0b 40 ff ?'?N??eLdK((??@.
20: 06 9b d1 7c 88 13 e8 03 00 80 00 80 9d 80 5b 99 ???|????.?.???[?
30: 4e 02 09 f7 09 09 09 14 0b 56 ec 09 4f 13 0a 00 N????????V??O??.
40: 8e 00 7e 00 00 07 72 00 64 00 64 00 64 00 00 00 ?.~..?r.d.d.d...
50: 00 80 00 80 00 80 00 80 00 80 00 80 00 80 00 80 .?.?.?.?.?.?.?.?
60: b1 7b eb 7f 0a 00 ed 2b 00 00 00 00 00 00 00 00 ?{???.?+........
70: e6 80 00 80 26 86 e0 7c 27 01 00 00 00 00 00 00 ??.?&??|'?......
since i2cdump only dumps 128 bytes instead of 256, let's use i2cget instead:
i2c-tools> i2cget --chip=0x50 --register=0 --length=256
0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0x52 0x00 0x22 0x01 0xf0 0x05 0x04
0x10 0x27 0x1f 0x4e 0x08 0x07 0x65 0x4c 0x64 0x4b 0x28 0x28 0x0a 0x0b 0x40 0xff
0x06 0x9b 0xd1 0x7c 0x88 0x13 0xe8 0x03 0x00 0x80 0x00 0x80 0x9d 0x80 0x5b 0x99
0x4e 0x02 0x09 0xf7 0x09 0x09 0x09 0x14 0x0b 0x56 0xec 0x09 0x4f 0x13 0x0a 0x00
0x8e 0x00 0x7e 0x00 0x00 0x07 0x72 0x00 0x64 0x00 0x64 0x00 0x64 0x00 0x00 0x00
0x00 0x80 0x00 0x80 0x00 0x80 0x00 0x80 0x00 0x80 0x00 0x80 0x00 0x80 0x00 0x80
0xb1 0x7b 0xeb 0x7f 0x0a 0x00 0xed 0x2b 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0xe6 0x80 0x00 0x80 0x26 0x86 0xe0 0x7c 0x27 0x01 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x9d 0x7f 0x00 0x80 0x00 0x80 0x00 0x80 0x00 0x80 0x00 0x00 0x00 0x00 0x00 0x00
0x0d 0x00 0x02 0x10 0x0d 0x00 0x03 0x20 0x20 0x00 0x03 0x20 0x20 0x00 0x03 0x10
0x41 0x00 0x03 0x08 0x41 0x00 0x03 0x05 0x41 0x00 0x03 0x05 0x0d 0x00 0x02 0x20
0x00 0x80 0x00 0x80 0x00 0x80 0x00 0x80 0x00 0x80 0xd2 0x7f 0x20 0x80 0x34 0x80
0x00 0x80 0xd0 0x07 0xd0 0x07 0x00 0x00 0x5a 0x45 0x7c 0x0f 0x05 0xc0 0x00 0x00
now initialize the screen (as traced):
i2cset --chip=0x3e --register=0x84 0x03
i2cset --chip=0x3e --register=0x82 0x00
i2cset --chip=0x3e --register=0x8A 0x00
i2cset --chip=0x3e --register=0x86 0x00
# clear the screen
i2cset --chip=0x3e --register=0x80 0x00 00 00 00 00 00 00 00 00
i2cset --chip=0x3e --register=0x80 0x08 00 00 00 00 00 00 00
i2cset --chip=0x3e --register=0x80 0x0F 00 00 00 00 00 00 00 00
# display all segments
i2cset --chip=0x3e --register=0x80 0x00 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
i2cset --chip=0x3e --register=0x80 0x08 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
i2cset --chip=0x3e --register=0x80 0x0F 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
APO
To disable the auto power off of the Aneng 623, hold the mA/A pad while power it on. There will be 4 fast beeps before the normal single boot beep, and the clock symbol on the top left off the screen should be off.
Sadly the DMM still repeatedly beeps after 14 minutes, and again after 1 minute, like if it were shutting down, but just does not power off.
Curiously the EEPROM content is very similar to the one for the DTM0660L DMM IC. I think they re-used it just because the calibration and configuration tools for similar DMM already existed. According to the datasheet, the auto power off is configured in minutes at address 0xFB. The current value is 0x0f, which matches the behaviour. I set it to 0 to disable power off.
i2cset --chip=0x50 --register=0xfb 0x00
E (1034055) i2c.master: I2C transaction unexpected nack detected
E (1034055) i2c.master: s_i2c_synchronous_transaction(872): I2C transaction failed
E (1034055) i2c.master: i2c_master_transmit(1074): I2C transaction failed
W (1034055) cmd_i2ctools: Write Failed
The write protect pin 7 is set high by the DMM IC, preventing writes. I briefly short it in circuit to ground to re-enable writes (the DMM IC survived this short short).
i2c-tools> i2cset --chip=0x50 --register=0xfb 0x00
I (1444165) cmd_i2ctools: Write OK
i2c-tools> i2cget --chip=0x50 --register=0 --length=256
0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0x52 0x00 0x22 0x01 0xf0 0x05 0x04
0x10 0x27 0x1f 0x4e 0x08 0x07 0x65 0x4c 0x64 0x4b 0x28 0x28 0x0a 0x0b 0x40 0xff
0x06 0x9b 0xd1 0x7c 0x88 0x13 0xe8 0x03 0x00 0x80 0x00 0x80 0x9d 0x80 0x5b 0x99
0x4e 0x02 0x09 0xf7 0x09 0x09 0x09 0x14 0x0b 0x56 0xec 0x09 0x4f 0x13 0x0a 0x00
0x8e 0x00 0x7e 0x00 0x00 0x07 0x72 0x00 0x64 0x00 0x64 0x00 0x64 0x00 0x00 0x00
0x00 0x80 0x00 0x80 0x00 0x80 0x00 0x80 0x00 0x80 0x00 0x80 0x00 0x80 0x00 0x80
0xb1 0x7b 0xeb 0x7f 0x0a 0x00 0xed 0x2b 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0xe6 0x80 0x00 0x80 0x26 0x86 0xe0 0x7c 0x27 0x01 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x9d 0x7f 0x00 0x80 0x00 0x80 0x00 0x80 0x00 0x80 0x00 0x00 0x00 0x00 0x00 0x00
0x0d 0x00 0x02 0x10 0x0d 0x00 0x03 0x20 0x20 0x00 0x03 0x20 0x20 0x00 0x03 0x10
0x41 0x00 0x03 0x08 0x41 0x00 0x03 0x05 0x41 0x00 0x03 0x05 0x0d 0x00 0x02 0x20
0x00 0x80 0x00 0x80 0x00 0x80 0x00 0x80 0x00 0x80 0xd2 0x7f 0x20 0x80 0x34 0x80
0x00 0x80 0xd0 0x07 0xd0 0x07 0x00 0x00 0x5a 0x45 0x7c 0x00 0x05 0xc0 0x00 0x00
Since the DMM while always be connected to power, and doesn't need to save any, I also disabled the timeout for the backlight.
i2c-tools> i2cset --chip=0x50 --register=0xfc 0x00
I (2981965) cmd_i2ctools: Write OK
You probably could also use the same tools as for the UT210E for EEPROM modifications.
DMM
The main board is marked FSJ-H9. Aneng just branded it and put its logo on the back of the LCD. I replaced this logo with my own.
The main DMM IC marking has been lasered off, but it's in an QFN-68 package instead of an epoxy blob. This unusual package points to a HY16F19. But the pinout only partially matches (the I2C interface does, but not the crystal). There is a second pin header interface on the board, exposing P1.0, P1.1, and P1.7. On other DMM ICs such as DTM0660, these are for the PSCK, PSDI, and PSDO signals for programming it. I did no try the ISP bootloader to read out the firmware.