Just to confirm you mean the addresses are in binary, so a one byte value from 0 to 255, not a string of text like "01010101". Or have I read it wrong?Right, a one byte binary value, 0 to 255. Not a string representing bits or a decimal or anything ASCII. It also means the GPIB implementation you're using needs to be 8-bit clean for this to work. Granted, it's not consistent with the documented commands, but I guess they didn't care since it's undocumented and simpler to implement with a single byte.
Thanks for the effort you put into this including the restoration of the trashed cal data proving it works. :-+.Of course! After I discovered I trashed my calibration, I was *really* committed to finding how the write works.
And as you say there are plenty of these meters still in service.
I just (very quickly) wrote a Windows program to read/write the calibration block. It needs a very recent version of the NI or Keysight VISA libraries. I've tested it with a NI USB GPIB adapter.Thanks for picking up the ball to write something that makes this method accessible for 3478A owners.
The breakdown of the SRAM makes sense.
But even if you could figure out the encoding and the checksum, how do you know what the factory default values should be?
http://hpmuseum.org/forum/thread-8061-post-71213.html#pid71213 (http://hpmuseum.org/forum/thread-8061-post-71213.html#pid71213)
There are so many uncertainties with claims as yet to be demonstrated, and for all you know, the undocumented command "W" may be returning an error bytes from Global Variables Iberr or ibsta and yes the logic analyser will be reading the same bytes returned. That, I am afraid cannot be taken as an affirmation of correctness.
In the other post, dfrederickson wrote;
Quote "Now I need to calibrate one parameter at a time and see which data changes, then figure out how the constants and parity/checksum are encoded. Unfortunately the 3478 responds to the B2 command with the B1 command status. Dave"
unless you know the location of each parameter and the exact representation taking into account any of the endians, example enter 41.2 represented at location X as 0x34, 0x31, 0x2E, 0x32, "yy" checksum, otherwise is doubtful the application and usability of it.
(https://www.eevblog.com/forum/repair/hp-3478a-how-to-readwrite-cal-sram/?action=dlattach;attach=306110;image)
I do know the location of each parameter. Now I just need to figure out the encoding.
Dave
There are so many uncertainties with claims as yet to be demonstrated, and for all you know, the undocumented command "W" may be returning an error bytes from Global Variables Iberr or ibsta and yes the logic analyser will be reading the same bytes returned. That, I am afraid cannot be taken as an affirmation of correctness.The logic analyzer was attached to the data, address, and control lines of the SRAM (U512) and captured each nibble stored at each address. How to set up the logic analyzer capture was discussed in a different thread a couple of years ago:
Ok, read your thread at hpmuseum.The breakdown of the SRAM makes sense.
But even if you could figure out the encoding and the checksum, how do you know what the factory default values should be?
Hmm, let's see. The input response is linear and the equation for a line is y=mx+b. Constants are stored for Zero and Gain, so, from the HP Journal article for the 3468:
...
Well, and then there's always the brute force method. If you're right that there's only 16 bits of ECC, how long will it take to write and test all the possible ECC values (or half, on average)?
It would be nice if someone could write a python or some other multi-platform method that implements the above in a friendly way. There's a lot 3478A's out there. It would make battery replacement a lot less stressful if you could back up the SRAM first and then restore it when done. No more isolated soldering irons, etc. Or even better, it would be good to make a backup *before* the battery goes dead.
The python script works for me and the data matches my clunky scripts - thanks!It would be nice if someone could write a python or some other multi-platform method that implements the above in a friendly way. There's a lot 3478A's out there. It would make battery replacement a lot less stressful if you could back up the SRAM first and then restore it when done. No more isolated soldering irons, etc. Or even better, it would be good to make a backup *before* the battery goes dead.
I'm attaching a little Python script that pulls the SRAM values out and drops them to stdout. Use like this:
python cal-3478a devicename > mycal
This depends on a properly working linux-gpib setup, and devicename must be a properly configured device in /etc/gpib.conf. No multi-platform GPIB out there, as far as I know.
Thanks so much for working this out -- would hate for my 3478A to die on me. At least now I have a backup! The battery seems to be doing OK, so perhaps I don't need to replace it yet?
@MarkL et allSounds like a fun challenge, but unfortunately I don't have a 3457A.
Now we "just" need to reveal the HP3457's secrets ;)
PHK did the 3458A , and you did the 3478A
Who's doing the 3457A
/Bingo
I did look at the ROM image that's available on KO4BB with "strings" and "xxd". It looks like there's a ROM monitor that can be accessed somehow. That might provide a path to read/write the NVRAM (U511).
0000000: 4f 40 40 40 46 41 41 42 41 4f 4f 40 4d 46 40 40 O@@@FAABAOO@MF@@
0000010: 40 40 45 49 42 41 40 43 45 4e 46 40 40 40 40 40 @@EIBA@CENF@@@@@
0000020: 46 42 41 40 4e 4e 4d 4a 49 49 49 49 49 44 42 41 FBA@NNMJIIIIIDBA
0000030: 4c 4c 40 4b 43 49 49 49 49 49 49 42 40 45 4f 44 LL@KCIIIIIIB@EOD
0000040: 4a 4f 40 40 40 40 40 40 40 40 40 40 40 4f 4f 49 JO@@@@@@@@@@@OOI
0000050: 49 49 45 49 45 42 4d 45 41 4e 4a 4e 49 49 49 49 IIEIEBMEANJNIIII
0000060: 46 48 41 4c 42 4e 42 4a 4e 49 49 49 49 49 46 41 FHALBNBJNIIIIIFA
0000070: 4c 43 4e 45 4a 49 40 40 40 40 40 40 41 4c 42 42 LCNEJI@@@@@@ALBB
0000080: 45 4e 49 40 40 40 40 40 40 41 4c 40 4f 4d 4d 46 ENI@@@@@@AL@OMMF
0000090: 49 49 49 49 49 49 41 4c 41 40 4f 4a 4c 49 49 49 IIIIIIALA@OJLIII
00000a0: 49 49 49 41 4c 40 43 43 4b 46 49 49 49 49 49 49 IIIAL@CCKFIIIIII
00000b0: 40 45 43 45 45 4b 47 40 40 40 44 43 49 43 42 4c @ECEEKG@@@DCICBL
00000c0: 43 40 4d 4b 40 40 40 40 44 44 43 42 4d 45 4e 4d C@MK@@@@DDCBMENM
00000d0: 42 40 40 40 40 40 40 40 40 40 40 40 4f 4f 49 49 B@@@@@@@@@@@OOII
00000e0: 49 45 49 45 43 4e 42 4e 44 4a 4c 40 40 40 40 40 IEIECNBNDJL@@@@@
00000f0: 40 40 40 40 40 40 4f 4f 40 40 40 40 40 40 40 40 @@@@@@OO@@@@@@@@
#!/usr/bin/python
from functools import partial
import sys
with open(sys.argv[1], 'r') if len(sys.argv) > 1 else sys.stdin as file:
for byte in iter(partial(file.read, 1), b''):
sys.stdout.write(chr(ord(byte)-64))
Note: I have read again the service manual, and now I understand why the did said 'CAUTION: do not send program codes "W" and/or "X" ... these codes can, under certain conditions, uncalibrate the instrument'Ah, good catch! I didn't notice that in the manual, but it certainly provided a clue. In my experimentation I never found any form of the "W" command that would write to memory. Since they mentioned "W" and "X", it wouldn't have killed them to document those commands and, for that matter, similar cal backup commands for a lot of other equipment. Tektronix is also quite guilty of hiding such useful commands.
...What are you trying to do?
The 8048 is quite weird: without CMP or SUB instruction, and also with those pages, mb0/mb1 selector, and bit 12 of program counter. I think I will not be able to find how it works. Is there any thread or progress about that? when I use strings on the ROM I cannot get any useful data. I will need to read the schematics more in detail.
The calibration procedure needs so many kinds of expensive calibration devices (in AC,DC,ohms, etc...) that it doesn't make any sense to have such easy-to-turn calibration switch in the front panel. How many devices should have been uncalibrated by mistake?.Our 3478's have a calibration sticker over the front-panel switch, plus, undocumented commands need to be sent, so I'd say not very many.
Do they did that on purpose to increase earnings from maintenance services?Most folks get their instruments calibrated by a third party, so probably not.
If you're trying to discover the CRC/ECC algorithm, I think you're going to need a logic analyzer attached to a running meter as I described previously.
As far as I know, there is no NI driver for it, so I'm using direct COM port communication.
@@@@BAIBMLOMKL@@
@@BBBLDNBMI@@@@@
BBMMMAMCIIIIIEBM
@MLJEIIIIIIBMCMA
JI@@@@@@@@@@@OO@
@@FFCADAACNFIIIH
GIALLEAJMIIIIHH@
ECC@L@IIIIIHALL@
AK@IIIIII@EDEMJN
IIIIIH@EDCDKJIII
IIIALL@LJDIIIIII
@EDBEKI@@@BFBCLC
A@NB@@@@BFCLEAEM
M@@@@@@@@@@@OO@@
@FFCBDBBCNC@@@@@
@@@@@@OO@@@@@@@@
I have been playing with Pigrew's windows C# program (from https://github.com/pigrew/HP3478Ctrl )
I forked my own version at https://github.com/iainkwhite/HP3478Ctrl
and after tinkering a bit, managed to read my cal data.
Sorry. Yes, the adapter will need a driver to interface to LabVIEW. It might be easier to just buy an adapter off eBay, like I did.I had considered that option, but everything I have seen on there so far costs more than the meter did!
Thanks pigrew!! I just downloaded your program and successfully read the SRAM from my 3478 meter.Well,
Has anyone tried to write their values back using your program yet?
I am getting ready to try to replace the battery in my meter, and in case I lose my config, I'd like to know if it works.
I guess I'm gun shy to try it yet. :) I don't like being the guinea pig. LOL
Here are my SRAM values, in case someone is trying to analyze data between all of our posts.
@@@@A@HBCM@MMG@@@@ACBBNENMFIIIII
IBCNDAKAIIIIIABBAB@LJIIIIIGBCAAB
LB@@@@@@@@@@@OO@@@DIGB@MLELKIIII
CB@EC@MLAIIIIID@DDDOKC@@@@@@@ED@
COC@@@@@@@EBONMK@@@@@@@EB@@OH@@@
@@@@ECCLNH@@@@@@ALADMN@IIIIFGCDE
EEKHIIIIIDCCDBCKO@@@@@@@@@@@OO@@
@CAICBLE@ML@@@@@@@@@@@OO@@@@@@@@
Thanks again to everyone involved in coming up with this solution to our problem!!!!
$ ./cal-3478a.py hp3478a > cal.txt
$ xxd cal.txt
00000000: 4040 4040 4041 4141 4141 4f4f 4d4c 4040 @@@@@AAAAAOOML@@
00000010: 4040 4040 4141 4144 444f 4440 4040 4040 @@@@AAADDOD@@@@@
00000020: 4141 414e 4240 4e4c 4949 4949 4943 4142 AAANB@NLIIIIICAB
00000030: 434c 454b 4849 4949 4949 4941 424f 444f CLEKHIIIIIIABODO
00000040: 4a44 4040 4040 4040 4040 4040 4040 4049 JD@@@@@@@@@@@@@I
00000050: 4949 4843 4941 4444 404e 4b49 4949 4949 IIHCIADD@NKIIIII
00000060: 4049 4045 4144 424c 4649 4949 4949 4240 @I@EADBLFIIIIIB@
00000070: 4542 4f42 4b48 4949 4949 4949 4045 4e41 EBOBKHIIIIII@ENA
00000080: 454b 4049 4949 4949 4940 4445 4244 4b4a EK@IIIIII@DEBDKJ
00000090: 4040 4040 4041 4045 4344 4f4e 4340 4040 @@@@@A@ECDONC@@@
000000a0: 4040 4040 4544 4c4e 4d4c 4040 4040 4041 @@@@EDLNML@@@@@A
000000b0: 4045 4545 424e 4d49 4949 4842 4242 424c @EEEBNMIIIHBBBBL
000000c0: 4c4e 4a4e 4949 4949 4842 4242 4e4c 414b LNJNIIIIHBBBNLAK
000000d0: 4240 4040 4040 4040 4040 4040 4040 4949 B@@@@@@@@@@@@@II
000000e0: 4948 4349 4245 4045 4f4b 4540 4040 4040 IHCIBE@EOKE@@@@@
000000f0: 4040 4040 4040 4040 4040 4042 4040 4040 @@@@@@@@@@@B@@@@
device {
minor = 0
name = "hp3478a"
pad = 1
sad = 1
}
I have been playing with Pigrew's windows C# program (from https://github.com/pigrew/HP3478Ctrl )
I forked my own version at https://github.com/iainkwhite/HP3478Ctrl
and after tinkering a bit, managed to read my cal data.
Thanks for the changes, I've merged most of the changes back into my branch, and posted a new binary:
https://github.com/pigrew/HP3478Ctrl/releases/tag/v0.20170630 (https://github.com/pigrew/HP3478Ctrl/releases/tag/v0.20170630)
-Nathan
Miti,
Did you replace your battery while powered on, or did you back up the ram, change battery, and then restore ram?
I backed up my ram, but haven't changed out the battery yet. Guess I'm chicken. LOL :D
I found a way to read and write the cal SRAM on the 3478A via the GPIB interface. It's an old question on how to (easily) backup the calibration on these devices, and I'm not aware that anyone has figured it out yet.
I was inspired to look for hidden GPIB commands by this post:
@@@@CA@BLLLNLG@@@@CABLLCOLO@@@@@DBLLOELMIIIIIDAEBAOKF@@@@@@AEBMNML@@@@@@@@@@@OOIIIE@BADODEL@IIII@D@E@MNKGIIIIIA@EDNNJLIIIIII@ECDDKIIIIIII@EABLKEIIIIII@EBBOKAIIIIII@EBMAKDIIIIII@EBDOJO@@@BF@CNOE@MB@@@@BECN@@MMJ@@@@@@@@@@@OOIIIE@BCLCOBKJ@@@@@@@@@@@OO@@@@@@@@
Calibration data checksum test:
@@@CA@BLLLNLG : CkSum = (199 + 56) Checksum OK.
@@@@CABLLCOLO : CkSum = (207 + 48) Checksum OK.
@@@@@DBLLOELM : CkSum = (205 + 50) Checksum OK.
IIIIIDAEBAOKF : CkSum = (182 + 73) Checksum OK.
@@@@@@AEBMNML : CkSum = (220 + 35) Checksum OK.
@@@@@@@@@@@OO : CkSum = (255 + 0) Checksum OK.
IIIE@BADODEL@ : CkSum = (192 + 63) Checksum OK.
IIII@D@E@MNKG : CkSum = (183 + 72) Checksum OK.
IIIIIA@EDNNJL : CkSum = (172 + 83) Checksum OK.
IIIIII@ECDDKI : CkSum = (185 + 70) Checksum OK.
IIIIII@EABLKE : CkSum = (181 + 74) Checksum OK.
IIIIII@EBBOKA : CkSum = (177 + 78) Checksum OK.
IIIIII@EBMAKD : CkSum = (180 + 75) Checksum OK.
IIIIII@EBDOJO : CkSum = (175 + 80) Checksum OK.
@@@BF@CNOE@MB : CkSum = (210 + 45) Checksum OK.
@@@@BECN@@MMJ : CkSum = (218 + 37) Checksum OK.
@@@@@@@@@@@OO : CkSum = (255 + 0) Checksum OK.
IIIE@BCLCOBKJ : CkSum = (186 + 69) Checksum OK.
@@@@@@@@@@@OO : CkSum = (255 + 0) Checksum OK.
I've just recently found this thread. I don't check EEVBLOG very often. Im very late geting to this party :(I know, the traffic on these forums is insane - come back after a few days, there's enough "recent posts" to fill a few pages !
Nice !
can't wait to try this on my unit. In the meantime I've written a small utility that verifies checksums and dumps each cal "entry" . Not super useful yet but it's mainly a starting point for when we figure out what each cal entry does.
This way we can play with the calibration entries and see what ranges they affect. No risk at all now that we know how to restore it.Agreed. It could also be done simply be setting one range on the dmm, and writing bogus entries to the cal RAM until the reading changes.
Looking at all the dumps posted and saved from my meters, there are 3 entries that are always @@@@@@@@@@@OO so I assume they are not usedGood observation, and my analysis of the firmware agrees - there are no references to those 3 entries (5, 0x10 and 0x12)
**** \dev\hp3478\hp3478a_utils\hp3478util.exe
**** (c) 2018 fenugrec
entry 00: 0 0 0 2 1 9 2 D C F D
entry 01: 0 0 0 0 2 2 2 C 4 E 2
entry 02: 0 0 0 0 0 2 2 D D D 1
entry 03: 9 9 9 9 9 5 2 D 0 D C
entry 04: 9 9 9 9 9 9 2 D 3 D 1
entry 05: 0 0 0 0 0 0 0 0 0 0 0
entry 06: 0 0 0 6 6 3 1 4 1 1 3
entry 07: 9 9 9 8 7 9 1 C C 5 1
entry 08: 9 9 9 9 8 8 0 5 3 3 0
entry 09: 9 9 9 9 9 8 1 C C 0 1
entry 0A: 9 9 9 9 9 9 0 5 4 5 D
entry 0B: 9 9 9 9 9 8 0 5 4 3 4
entry 0C: 9 9 9 9 9 9 1 C C 0 C
entry 0D: 9 9 9 9 9 9 0 5 4 2 5
entry 0E: 0 0 0 2 6 2 3 C 3 1 0
entry 0F: 0 0 0 0 2 6 3 C 5 1 5
entry 10: 0 0 0 0 0 0 0 0 0 0 0
entry 11: 0 0 0 6 6 3 2 4 2 2 3
entry 12: 0 0 0 0 0 0 0 0 0 0 0
First 6 nibbles = Gain, next 3 = Offset, last 2 = Checksum?Not quite, my tool already strips the checksums - what is printed is all data.
OK, so I couldn't wait until the weekend and today after work I played with my "lab rat" again and check this out!Awesome !! And you did a pretty thorough job, thanks for that.
Cal entry # Rangehehe I did a double take on the unused entries but simply because you started your numbering at 1, where I used 0 !
...
17 Not used
18 300 mA and 3A AC
19 Not used...
I also experimented with the constants for the 30V range. I used a 9V battery to see changes. I've attached the results. The gain doesn't really do what I expected so it needs more thinkingInteresting - I'll see if I can find some hints in the firmware.
The 999 thing is like the zero level is at 1000000 but you only see the last 6 digits. [...]
So you say the calculations are done in BCD? Looks stupid to me...
So you say the calculations are done in BCD? Looks stupid to me...
Hehe, say not stupid, but rather out of fashion.
Interesting, the offset constants seem to be BCD but the "gain" is in hex. Maybe all the calculations that involve mult/div are done in hex, then it comes the conversion to BCD and the offset is applied right at the end.
13F1C (your initial gain)
23f1c
03f1c
14f1c (change just the second digit)
13e1c (change just the third)
# offset gain? range
00 000109 14F40 30 mV DC
01 000009 13411 300 mV DC
02 000001 134F5 3 V DC
03 999994 13F1C 30 V DC
04 999999 13FE1 300 V DC
05 000000 00000 (Not used)
06 000324 135D3 ACV
07 999977 05D30 30 Ohm 2W/4W
08 999998 04210 300 Ohm 2W/4W
09 000000 042F2 3 KOhm 2W/4W
0A 000000 04F35 30 KOhm 2W/4W
0B 999999 0403F 300 KOhm 2W/4W
0C 999999 04F0E 3 MOhm 2W/4W
0D 999999 03552 30 MOhm 2W/4W
0E 999844 2315D 300 mA DC
0F 999984 23D24 3A DC
10 000000 00000 (Not used)
11 000118 23EF1 300 mA/3A AC
12 000000 00000 (Not used)
See how the "gain" values are similar within a same mode !
Quite possible. Would you have time to run a few more tests ? As long as your 9V battery is stable (ideally to the last digit) that would be fine. Or maybe on one of the resistance scales, the readings will probably be even more stable .
I'll have to use a 3V reference that I have (a 0.02% linear regulator). Give me the values that you want to try for the 3V range.
134F5 (orig value)
234F5
034F5
144F5 (2nd digit)
135F5 (3rd digit)
optional:
134E5 (4th)
134F6 (5th)
The last two (4th and 5th digits), not really necessary I think.Here you go.Thanks!
reading theor. error
300054 300072 -17.7864747599815
303014 303037 -22.7216222800198
297093 297107 -13.8513272400014
300350 300257 92.9050785200088
300083 300084 -0.684941919986159
300051 300071 -20.0626136400388
300054 300072 -17.8317160800216
Do you think there's a fixed, ideal constant that is expected by design and the calibration constant correct that fixed constant?Well that's what my model indicates, and it would certainly be reasonable : they knew the actual realized gain is going to be very very close to their design gain. If they were to save the exact gain factor determined during calibration, it would need a lot of significant digits - and that's a waste of cal RAM !
00000000 13 05 0C 06 20 14 05 13 14 20 20 20 00 55 43 20 12 01 0D 20 06 01 09 0C 20 00 55 43 20 12 0F 0D ¶¶¶¶ ¶¶¶¶ ¶UC ¶¶¶ ¶¶¶¶ ¶UC ¶¶¶
00000020 20 06 01 09 0C 20 00 FA FA FA FA FA FA FA FA FA FA FA FA 00 15 0E 03 01 0C 09 02 12 01 14 05 04 ¶¶¶¶ ¶úúúúúúúúúúúú¶¶¶¶¶¶¶¶¶¶¶¶¶
00000040 00 81 04 20 0C 09 0E 0B 20 06 01 09 0C 00 81 04 20 14 05 13 14 20 06 01 09 0C 00 08 10 09 02 20 ¶¶ ¶¶¶¶ ¶¶¶¶¶¶ ¶¶¶¶ ¶¶¶¶¶¶¶¶¶
00000060 01 04 12 53 20 54 4F 00 20 20 0F 16 0C 04 20 20 00 20 20 20 20 20 20 20 20 20 20 20 20 00 13 05 ¶¶¶S TO¶ ¶¶¶¶ ¶ ¶¶¶
00000080 0C 06 20 14 05 13 14 20 0F 0B 00 ¶¶ ¶¶¶¶ ¶¶¶
00000000 53 45 4C 46 60 54 45 53 54 60 60 60 40 55 43 60 52 41 4D 60 46 41 49 4C 60 40 55 43 60 52 4F 4D SELF`TEST```@UC`RAM`FAIL`@UC`ROM
00000020 60 46 41 49 4C 60 40 3A 3A 3A 3A 3A 3A 3A 3A 3A 3A 3A 3A 40 55 4E 43 41 4C 49 42 52 41 54 45 44 `FAIL`@::::::::::::@UNCALIBRATED
00000040 40 01 44 60 4C 49 4E 4B 60 46 41 49 4C 40 C1 44 60 54 45 53 54 60 46 41 49 4C 40 48 50 49 42 60 @¶D`LINK`FAIL@ÁD`TEST`FAIL@HPIB`
00000060 41 44 52 53 60 54 4F 40 60 60 4F 56 4C 44 60 60 40 60 60 60 60 60 60 60 60 60 60 60 60 40 53 45 ADRS`TO@``OVLD``@````````````@SE
00000080 4C 46 60 54 45 53 54 60 4F 4B 40 LF`TEST`OK@
--- GPIB6.1.ino
+++ GPIB6.1.new.ino
@@ -226,8 +226,8 @@
case CR:
case NL:
- // if (isesc) goto loadchar;
- if (isesc) { Serial.println("CR or LF inserted");goto loadchar; }
+ if (isesc) goto loadchar;
+ //if (isesc) { Serial.println("CR or LF inserted");goto loadchar; }
*comp = NULL; // replace USBeos with null
if (gotplus == 2) { // got a "++" at the beginnig: its a command!
Has anyone had luck using an Arduino based GPIB adapter to accomplish this?
Output looks to in keeping with what others have so I think it is all good, but I've not tried writing data back yet.
--- HP3478A-SRAM.txt 2018-04-26 00:57:24.031777400 +0200
+++ HP3478A-SRAM_2.txt 2018-04-26 00:58:02.302675400 +0200
@@ -104,10 +104,7 @@
# This code reads the sram from HP 3478a and stores output in 2 arrays
for addr in range(elements):
- cmd = "W" + chr(addr)
- # If we are at the ESC char then add again to allow it to pass through to Device
- if addr == 27:
- cmd = cmd + chr(addr)
+ cmd = "W" + chr(27) + chr(addr)
ser.write(cmd +'\r\n')
out = ser.read(1)
0000000: 4c 40 40 40 43 45 47 42 4f 4d 4c 41 4c 4c 40 40 L@@@CEGBOMLALL@@
0000010: 40 40 43 45 42 4f 40 43 45 4d 4e 40 40 40 40 40 @@CEBO@CEMN@@@@@
0000020: 44 42 4f 4e 4f 42 4c 4b 49 49 49 4c 49 44 42 4f DBONOBLKIIILIDBO
0000030: 4d 44 4d 49 4f 49 49 49 49 49 49 42 4e 45 4e 44 MDMIOIIIIIIBNEND
0000040: 4a 42 40 40 40 40 40 40 40 40 40 40 40 4f 4f 49 JB@@@@@@@@@@@OOI
0000050: 49 48 47 40 44 42 4c 45 4f 41 4b 47 49 49 49 48 IHG@DBLEOAKGIIIH
0000060: 44 47 40 45 45 42 44 4c 41 49 49 49 49 48 45 41 DG@EEBDLAIIIIHEA
0000070: 4c 4e 4d 45 4a 41 49 49 49 49 49 48 40 45 45 43 LNMEJAIIIIIH@EEC
0000080: 45 4b 48 49 49 49 49 49 48 40 45 45 41 4e 4b 41 EKHIIIIIH@EEANKA
0000090: 49 49 49 49 49 48 40 45 43 41 4c 4b 45 49 49 49 IIIIIH@ECALKEIII
00000A0: 49 49 48 40 45 45 41 4e 4b 41 49 49 49 49 49 48 IIH@EEANKAIIIIIH
00000B0: 40 45 45 43 40 4b 4d 40 40 40 40 43 46 43 4f 45 @EEC@KM@@@@CFCOE
00000C0: 42 4c 4d 41 40 40 40 40 40 43 43 40 4d 42 42 4e BLMA@@@@@CC@MBBN
00000D0: 48 40 40 40 40 40 40 40 40 40 40 40 4f 4f 49 49 H@@@@@@@@@@@OOII
00000E0: 48 47 40 44 43 4d 41 45 41 4c 43 40 40 40 40 40 HG@DCMAEALC@@@@@
00000F0: 40 40 40 40 40 40 4f 4f 40 40 40 40 40 40 40 40 @@@@@@OO@@@@@@@@
0000000: 4c 40 40 40 43 45 47 42 4f 4d 45 41 4c 4c 40 40 L@@@CEGBOMEALL@@
0000010: 40 40 43 45 42 4f 40 43 45 4d 4e 40 40 40 40 40 @@CEBO@CEMN@@@@@
0000020: 44 42 4f 4e 4f 42 4c 4b 49 49 49 49 49 44 42 4f DBONOBLKIIIIIDBO
0000030: 4d 44 4d 49 4f 49 49 49 49 49 49 42 4e 45 4e 44 MDMIOIIIIIIBNEND
0000040: 4a 42 40 40 40 40 40 40 40 40 40 40 40 4f 4f 49 JB@@@@@@@@@@@OOI
0000050: 49 48 47 40 44 42 4c 45 4f 41 4b 47 49 49 49 48 IHG@DBLEOAKGIIIH
0000060: 44 47 40 45 45 42 44 4c 41 49 49 49 49 48 45 41 DG@EEBDLAIIIIHEA
0000070: 4c 4e 4d 45 4a 41 49 49 49 49 49 48 40 45 45 43 LNMEJAIIIIIH@EEC
0000080: 45 4b 48 49 49 49 49 49 48 40 45 45 41 4e 4b 41 EKHIIIIIH@EEANKA
0000090: 49 49 49 49 49 48 40 45 43 41 4c 4b 45 49 49 49 IIIIIH@ECALKEIII
00000A0: 49 49 48 40 45 45 41 4e 4b 41 49 49 49 49 49 48 IIH@EEANKAIIIIIH
00000B0: 40 45 45 43 40 4b 4d 40 40 40 40 43 46 43 4f 45 @EEC@KM@@@@CFCOE
00000C0: 42 4c 4d 41 40 40 40 40 40 43 43 40 4d 42 42 4e BLMA@@@@@CC@MBBN
00000D0: 48 40 40 40 40 40 40 40 40 40 40 40 4f 4f 49 49 H@@@@@@@@@@@OOII
00000E0: 48 47 40 44 43 4d 41 45 41 4c 43 40 40 40 40 40 HG@DCMAEALC@@@@@
00000F0: 40 40 40 40 40 40 4f 4f 40 40 40 40 40 40 40 40 @@@@@@OO@@@@@@@@
Thanks for your script, I tested it with an Arduino and while the output looks ok, the checksum verification with fenugrec's tool fails.
There are some more characters which require escaping (LF 10, Forward Slash 47 in my case), so I tried to just escape every character and the output now validates fine.
However you need also to remove or comment out the line 232 from GPIB6.1.ino which prints "CR or LF inserted" when you escape the CR/NL chars
--- GPIB6.1.ino
+++ GPIB6.1.new.ino
@@ -226,8 +226,8 @@
case CR:
case NL:
- // if (isesc) goto loadchar;
- if (isesc) { Serial.println("CR or LF inserted");goto loadchar; }
+ if (isesc) goto loadchar;
+ //if (isesc) { Serial.println("CR or LF inserted");goto loadchar; }
*comp = NULL; // replace USBeos with null
if (gotplus == 2) { // got a "++" at the beginnig: its a command!
[...] the two constants for each function and range have parity bits associated with them so that the 3468A's microprocessor can locate single-bit errors and detect double-bit errs. The processor can correct a single-bit error in a cal constant and the instrument will remain calibrated. If the processor detects more than a single-bit error, the CAL annun is displayed and the error bits are set [...]
see how the raw numbers correlate with the calibration constant.
entry # offset gain? range
00 000368 3EDC5 30 mV DC
get digit_n as hex;
if digit_n > 8, then factor_n = digit_n - 16
gain_const = 1 + (digit_1 / 100) + (digit_2 / 1000) + ... (digit_5 / 1E6);
So for the example above "3EDC5", we havegain_const = 1 + (3 / 100) + (-2 / 1000) + (-3 / 1E4) + (-4 / 1E5) + (5 / 1E6);
gain_const = 1.027665
That won't be necessary ! Just finished figuring out the gain constants, with the help of partial MAME emulation.
.
.
.
And, that's pretty much all there is to it.
That won't be necessary ! Just finished figuring out the gain constants, with the help of partial MAME emulation.
.
.
.
And, that's pretty much all there is to it.
Bravo :clap:
Amazing work Fenugrec!
Now we need an application where you say "I want to read 10 digits more on 3V DC" and it reads the constant, calculates, modifies and writes it back.
Pigrew,
Can you code something?
What do you mean by : "I want to read 10 digits more on 3V DC" you want a 10 digits resolution ???
coromonadalix, thanks for the tip. Any way to know which ones are fake? Also, do fake ones work at all? Almost all of them are listed as "new in box". If some of them are fakes, how to tell apart...It's usually hard to tell from photos and descriptions, but you can be pretty much guaranteed it's counterfeit if coming from China or Taiwan.
Thanks, this worked for me. But would be nice to see an interpretation of the cal values. :)I'm glad it worked. I doubt I will get around to updating the software any time soon (I don't have a business of changing 3478A batteries...). However, I would accept github pull requests.
HP5810a GPIB ethernet gateway
It seems that Steve's algorithm (or my implementation of it) fails when the gain is outside the range of 1 to 1.055555.
gain_const gain
13F1C 1.012906
fff1c 0.988906
88888 0.911112
Raw Gain
13F1C 1.012906
fff1c 0.988906
88888 1.088888
Raw Gain
13F1C 1.012906
fff1c 0.988906
88888 0.911112
Should I make the correction or should we look into this some more?
Raw Gain
13F1C 1.012906
fff1c 0.988906
88888 1.088888
Decode Value Encode Value
13F1C 1.012906 13F1c 1.012906
FFF1C 0.988906 0110F 1.001099
88888 1.088888 FFFFE 0.988888
function RevGain$(g)
'reverse gain. calculate gain encoded value in hex.
'Uncompressed gain in g. Returns encoded gain in RevGain$
gt=g-1 '?? 1 is a constant & not used in the calc. is this correct ??
RevGain$="" 'Build new string into a null string.
for i = 6 to 2 step -1
'Add any needed trailing 0's to get i digits in number
gd=val(right$(mid$(str$(gt)+"00000",1,i+2),1))
if gd>5 then
cd=gd+6
gt=gt+(10-gd)*10^-i
else
cd=gd
gt=gt-gd*10^-i
end if
gt=int((gt+(5*10^-11))*10^10)/10^10 'round off to fix compiler math error
RevGain$=dechex$(cd)+RevGain$ 'Build compressed gain hex string.
next i
end function
Would you or fenugrec be able to help me get the gain data properly re-packed? Also, let me know if I need to make changes in the unpack algorithm.
Would you or fenugrec be able to help me get the gain data properly re-packed? Also, let me know if I need to make changes in the unpack algorithm.
Sure, but as I mentioned we may be slightly wrong (or at least uncertain) about the decoding; it would be really good to do some kind of test as I described, before spending too much time on a possibly-wrong encoding implementation.
[...] I assume it won't matter which function or range is used. You only want the meter response to changes in the gain value.
00000
00700
00800
00900
00a00
00f00
90700
77777
88888
99999
And how do I send these raw gains? I would have to read the calibration constants, modify the gain for the 3V range, calculate the checksum, upload the new constants?
That's what I'm testing now. I modified my cal edit program to accept a raw gain value. I enter 0 for the offset and 5 hex digits for the gain. The program calculates the checksum and sends the new cal entry to the meter. I then log the new reading from the meter.
If you're interested I can put the modified program up on my web site.
Sure I'm interested. Even if you do this experiment, I still intend to do it in the weekend.
initial reading .68309
3K range default calibration: offset -1 gain 1.0036 (04C00)
Start: and End: are the calibrated resistance readings from the beginning and end of each test
Start: .68309
RawG Meter reading
00000 68064
00700 68112
00800 68009
00900 68016
00a00 68022
00f00 68056
90700 63346
77777 73356
88888 62013
99999 62769
End: .68307
Start: .68307
00000 68062
00700 68110
00800 68008
00900 68014
00a00 68021
00f00 68055
90700 63345
77777 73356
88888 62012
99999 62769
End: . 68307
Start: .68306
00000 68061
00700 68109
00800 68006
00900 68013
00a00 68020
00f00 68053
90700 63343
77777 73353
88888 62010
99999 62766
End: . 68304
Below is the data from three tests. The second test was the most stable.
gain const reading 'x' decode(x) Un-apply gain
(= reading / decode(x))
TEST SERIES 1
00000 68064 1.000000 68064.0
00700 68112 1.000700 68064.4
00800 68009 0.999200 68063.5
00900 68016 0.999300 68063.6
00a00 68022 0.999400 68062.8
00f00 68056 0.999900 68062.8
90700 63346 0.930700 68062.7
77777 73356 1.077777 68062.3
88888 62013 0.911112 68063.0
99999 62769 0.922223 68062.7
TEST SERIES 2
00000 68062 1.000000 68062.0
00700 68110 1.000700 68062.4
00800 68008 0.999200 68062.4
00900 68014 0.999300 68061.6
00a00 68021 0.999400 68061.8
00f00 68055 0.999900 68061.8
90700 63345 0.930700 68061.7
77777 73356 1.077777 68062.3
88888 62012 0.911112 68061.9
99999 62769 0.922223 68062.7
gain = 1
for cur=1 to 5
temp = clng("&h" & mid(gainstring, cur, 1)) ### this converts a single digit from the "raw gain constant" text string to a numerical value.
if (temp >= 8) then
temp = temp - 16
endif
rem digit 1 (cur = 1) is 1/100)
gain = gain + (temp / (10^(cur + 1)))
next cur
Initial reading 3.00048V 3V DC Range 30V DC Range Gain reported Correct gain
Initial offset -2
Initial gain 1.027762
00000 2.91943 2.9198 1.00000 1.00000 2.91943 2.9198
00700 2.92148 2.9219 1.0007 1.0007 2.919436395 2.919856101
00800 2.9171 2.9175 1.0008 0.9992 2.919435548 2.919835869
00900 2.91739 2.9178 0.9993 0.9993 2.919433604 2.919843891
00a00 2.91768 2.9181 0.9994 0.9994 2.919431659 2.919851911
00f00 2.91914 2.9195 0.9999 0.9999 2.919431943 2.919791979
90700 2.71712 2.7175 0.9307 0.9307 2.919436983 2.919845278
77777 Over 3.1469 1.077777 1.077777 0.00000 2.919806231
88888 2.65993 2.6603 1.088888 0.911112 2.919432518 2.919838615
99999 2.69237 2.6927 0.922223 0.922223 2.919434887 2.919792718
GainC is the compressed gain value used for the test
MeterDisp is the meter reading for the current GainC
GainNum is the uncompressed gain value
Calc-Gain is MeterDisp/GainNum. Should be 2.91943
GainC MeterDisp GainNum Calc-Gain
00000 2.91943 1.000000 2.91943
00700 2.92148 1.000700 2.919436
00800 2.9171 0.999200 2.919435
00900 2.91739 0.999300 2.919433
00a00 2.91768 0.999400 2.919431
00f00 2.91914 0.999900 2.919431
90700 2.71712 0.930700 2.919436
77777 OverRng 1.077777 ?
88888 2.65993 0.911112 2.919432
99999 2.69237 0.922223 2.919434
My gain unpack code is currently using "digit>8" not "digit>=8". I assume that I should switch this to "digit>=8"?yes, otherwise the raw constant "88888" wouldn't decode/unpack properly. As you saw, it corresponds to a gain of 0.911112 which is validated by many tests now.
C = R; //C will be the "almost calibrated" reading, just before the offset is applied.
K1 = 9;
// At the "1" digit, we're working at the 1/100 decimal position, so R is "decimal-shifted" 2 digits right.
// Since K1 >= 8, we need to subtract (16-9)=7 times the shifted raw reading.
C = C - ((16-9) * R/100);
K2 = 0;
//do nothing
K3 = 7:
// digit 3 : means "add 7 times", but now R is shifted 4 positions
C = C + (7 * R/10000);
//and the rest of the digits are 0, so do nothing.
//The equivalent operation is C = (1 * R) - (7 * 0.01 * R) + (7 * 0.00001 * R)
//can also be written as C = R * (1 - 0.07 + 0.00007) or
//of course, C = R * 0.9307
Also, I'd still like to know what range check to use for the gain. What limits should I set for user entered gain values?
77777 1.077777
88888 0.911112
The reverse process is sortof like a long division I guess ? I think it goes something like this. Assume all offsets are 0 for simplicity. The meter has a raw ADC reading 'R', and it knows the expected calibrated value 'C'.
- calculate error 'e = c - r' . Can be negative of course
- shift raw value right, i.e. divide by 10. First iteration needs to start at a 1/100 division. let's call it 'sr = r * (1/100)'
- how many times does 'sr' fit in 'e' ?
- if it fits 0 to 7 times, then that encodes directly to digit 1.
- if it fits -1 to -8 times, then "encode" that digit as (16 - <value>), so 0x0F for -1 to 0x08 for -8.
- if it fits 8 or 9 times, problem : those digits indicated negative values, so we need to cheat:
carry 10 to the digit to the left (by incrementing by 1 - careful if the digit was already 7, you'll need to do the same manoeuvre recursively), and set the current digit to (value - 10) i.e. -2 or -1.
In other words, use the fact that 8 * sr = (10 * sr) + (-2 * sr)- if it fits -9 times, same idea : borrow 10 from digit on the left, adjust, and continue.
- calculate new 'e' value for next loop, i.e. remainder. Right shift sr again and continue
I think that should work, conceptually at least. Interesting consequence of the +7/-8 limit on digits : some gain values can be encoded in more than one way, for example 0001C and 00006 both correspond to a gain of 1.000006 .
I've also been thinking about how to convert from floating point back to a raw gain, and I'm not sure there is a good way.
k1 = 0
k2 = 0
k3 = 0
k4 = 1
k5 = 'C' = -4
R = raw ADC reading,
delta = correction to apply
C = corrected value :
C = R + delta
delta = R * ( (K1 * 0.01) + (K2 * 0.001) + (K3 * 0.0001) .... + (K5 * 0.000 001))
######
all good ? in this case K1 to K3 are 0, so we can rewrite as
delta = R * ((1 * 0.00001) + (-4 * 0.000 001))
and then of course,
delta = R * (0.000006)
######
easy enough, I hope. This last value, 0.000006, I'll call it "k_factor" to distinguish it from the gain. So,
delta = R * k_factor
Remember from the beginning,
C = R + delta
C = R + R*k_factor
C = R * (1 + k_factor)
but we like to think about gain. What's gain ?
C = R * gain
so,
gain = 1 + k_factor
therefore "gain" in our example is 1.000006.
############
what's the opposite process ? Let's say for gain=1.049000 ? We want to determine the digits K1 to K5, such that
k_factor = (K1 * 0.01) + (K2 * 0.001) + (K3 * 0.0001) + (K4 * 0.00001) + (K5 * 0.000 001)
1) finding k_factor : super easy. Of course this can give a negative number, since "gain" can be <1.
k_factor = gain - 1 = 0.049000
2) how do you "solve" the equation to find K1 to K5 ?
2A) determine the desired k_factor = gain - 1 = 0.049000
2B) for digit K1, which corresponds to the position "0.04", can we solve (0.04 = K1 * 0.01) ? Of course. K1 = 4.
2C) for digit K2, corresponding to the position "0.009". Can we solve (0.009) = (K2 * 0.001) ?
yes, but we have a problem : we would like K2 = 9, but we can only have K values between -8 and +7.
What can we do ?
2D) well, 9 = (10 - 1). Serious math. what does that mean ?
k_factor = (K1 * 0.01) + (K2 * 0.001) + ...
k_factor = (4 * 0.01) + ((10 * 0.001) + (-1 * 0.001)) + ...
k_factor = (4 * 0.01) + (0.01 + (-1 * 0.001)) + ...
k_factor = (5 * 0.01) + (-1 * 0.001) + ...
see what happened ? I incremented K1, and set K2 = -1. All's good, we've made the digits fall in the valid range -8.... +7
the digits are now
K1 = 5
K2 = -1
2A3) : next digits are 0, thankfully. But it would be the same process.
##### note: if a carry/borrow operation causes a digit to fall outside the valid range, then another carry/borrow would have to be repeated with the next digit to the left.
2A5) we end up with a gain constant "5F000".
I've done some testing. The instrument does seem to handle the compressed gain in either format. My testing shows that both encoded gain values give the same instrument reading.Excellent, glad to hear.
I'm just not comfortable about writing different compressed gain data into the instrument for the same gain setting.
Fair point. The only theory I have is that the original algo tries to clamp each digit value to the range [-4...+5] i.e. allowing only C,D,E,F,0,1,...,5 . I checked a few cals (non exhaustive) and indeed the digits 6,7,8,9,A,B seem to be always absent. One reason to do this might be to limit rounding error propagation by keeping multiplications small (<= 5) ?
You're welcome to check against the annotated disassembly listing I have in my repo, but I find that reading hand-optimized BCD code is super tedious. Or you could emulate that portion of the code under MAME, but tracking 6-digit packed-BCD operations is also headache-inducing...
python3.8 -m venv venv
source venv/bin/activate
pip install --upgrade pip
pip install pyusb
pip install pyvisa
pip install pyvisa-py
pip install gpib-ctypes
#!/bin/env python3
import sys
import pyvisa
rm = pyvisa.ResourceManager()
dvm = rm.open_resource('GPIB::16::INSTR')
vals_per_line = 16
for addr in range(256):
dvm.write_raw(bytes([ord('W'), addr]))
val = dvm.read()
sys.stdout.write(val)
if ((addr + 1) % vals_per_line == 0):
sys.stdout.write('\n')
sys.stdout.write('\n')
dvm.close()
rm.close()
000001 40 40 40 40 46 47 41 4d 40 4e 4f 4c 47 >@@@@FGAM@NOLG< 00: offset=000067 raw_gain=1d0ef
00000e 40 40 0a 40 40 40 47 41 4d 4d 4f 4e 4c >@@.@@@GAMMONL< 01: offset=00a000 raw_gain=71ddf
00001b 40 40 40 40 40 40 0a 41 41 4d 4d 4d 4e >@@@@@@.AAMMMN< 02: offset=000000 raw_gain=a11dd
000028 4c 48 49 49 49 49 49 44 41 4c 0a 44 42 >LHIIIIIDAL.DB< 03: offset=c89999 raw_gain=941ca
000035 42 4b 49 49 49 49 49 49 49 41 4c 44 4f >BKIIIIIIIALDO< 04: offset=2b9999 raw_gain=9991c
000042 43 0a 4a 46 40 40 40 40 40 40 40 40 40 >C.JF@@@@@@@@@< 05: offset=3aa600 raw_gain=00000
00004f 40 40 40 40 49 0a 49 48 40 43 48 41 41 >@@@@I.IH@CHAA< 06: offset=00009a raw_gain=98038
00005c 41 42 43 4d 42 49 49 49 48 0a 48 48 40 >ABCMBIIIH.HH@< 07: offset=123d29 raw_gain=998a8
000069 45 41 4c 41 4b 49 49 49 49 49 48 48 40 >EALAKIIIIIHH@< 08: offset=51c1b9 raw_gain=99998
000076 0a 45 4d 45 44 4b 40 49 49 49 49 49 49 >.EMEDK@IIIIII< 09: offset=a5d54b raw_gain=09999
000083 40 45 4d 43 0a 4d 4a 47 49 49 49 49 49 >@EMC.MJGIIIII< 10: offset=05d3ad raw_gain=a7999
000090 48 40 45 4f 41 4f 4a 46 0a 49 49 49 49 >H@EOAOJF.IIII< 11: offset=805f1f raw_gain=a6a99
00009d 49 49 40 45 4f 42 40 4b 43 49 49 49 0a >II@EOB@KCIII.< 12: offset=9905f2 raw_gain=0b399
0000aa 49 49 48 40 45 4e 43 41 4b 43 49 49 49 >IIH@ENCAKCIII< 13: offset=99805e raw_gain=31b39
0000b7 49 49 48 0a 41 4c 4f 43 4c 49 4f 49 49 >IIH.ALOCLIOII< 14: offset=998a1c raw_gain=f3c9f
0000c4 49 48 44 45 42 4d 4c 0a 41 41 4b 46 49 >IHDEBML.AAKFI< 15: offset=98452d raw_gain=ca11b
0000d1 49 49 49 48 43 42 4c 44 42 43 4b 0a 49 >IIIHCBLDBCK.I< 16: offset=999832 raw_gain=c423b
0000de 40 40 40 40 40 40 40 40 40 40 40 40 40 >@@@@@@@@@@@@@< 17: offset=000000 raw_gain=00000
0000eb 49 49 0a 47 49 43 42 42 40 43 40 42 4d >II.GICBB@C@BM< 18: offset=99a793 raw_gain=22030
0000f8 41 40 40 40 40 40 0a 40 40 40 40 40 40 >A@@@@@.@@@@@@< 19: offset=100000 raw_gain=a0000
000105 40 40 40 40 40 40 40 40 40 40 0a >@@@@@@@@@@.< 20: offset=000000 raw_gain=0000a
000001 40 40 40 40 46 47 41 4d 40 4e 4f 4c 47 >@@@@FGAM@NOLG< 00: offset=000067 raw_gain=1d0ef gain=1.006979 crc=ff 30 mV DC
00000e 40 40 40 40 40 47 41 4d 4d 4f 4e 4c 40 >@@@@@GAMMONL@< 01: offset=000007 raw_gain=1ddfe gain=1.006688 crc=ff 300 mV DC
00001b 40 40 40 40 40 41 41 4d 4d 4d 4e 4c 48 >@@@@@AAMMMNLH< 02: offset=000001 raw_gain=1ddde gain=1.006668 crc=ff 3 V DC
000028 49 49 49 49 49 44 41 4c 44 42 42 4b 49 >IIIIIDALDBBKI< 03: offset=999994 raw_gain=1c422 gain=1.006422 crc=ff 30 V DC
000035 49 49 49 49 49 49 41 4c 44 4f 43 4a 46 >IIIIIIALDOCJF< 04: offset=999999 raw_gain=1c4f3 gain=1.006393 crc=ff 300 V DC
000042 40 40 40 40 40 40 40 40 40 40 40 40 40 >@@@@@@@@@@@@@< 05: offset=000000 raw_gain=00000 gain=1.000000 crc=00 <not used>
00004f 49 49 48 40 43 48 41 41 41 42 43 4d 42 >IIH@CHAAABCMB< 06: offset=998038 raw_gain=11123 gain=1.011123 crc=ff AC V
00005c 49 49 49 48 48 48 40 45 41 4c 41 4b 49 >IIIHHH@EALAKI< 07: offset=999888 raw_gain=051c1 gain=1.005061 crc=ff 30 Ohm 2W/4W
000069 49 49 49 49 48 48 40 45 4d 45 44 4b 40 >IIIIHH@EMEDK@< 08: offset=999988 raw_gain=05d54 gain=1.004754 crc=ff 300 Ohm 2W/4W
000076 49 49 49 49 49 49 40 45 4d 43 4d 4a 47 >IIIIII@EMCMJG< 09: offset=999999 raw_gain=05d3d gain=1.004727 crc=ff 3 kOhm 2W/4W
000083 49 49 49 49 49 48 40 45 4f 41 4f 4a 46 >IIIIIH@EOAOJF< 10: offset=999998 raw_gain=05f1f gain=1.004909 crc=ff 30 kOhm 2W/4W
000090 49 49 49 49 49 49 40 45 4f 42 40 4b 43 >IIIIII@EOB@KC< 11: offset=999999 raw_gain=05f20 gain=1.004920 crc=ff 300 kOhm 2W/4W
00009d 49 49 49 49 49 48 40 45 4e 43 41 4b 43 >IIIIIH@ENCAKC< 12: offset=999998 raw_gain=05e31 gain=1.004831 crc=ff 3 MOhm 2W/4W
0000aa 49 49 49 49 49 48 41 4c 4f 43 4c 49 4f >IIIIIHALOCLIO< 13: offset=999998 raw_gain=1cf3c gain=1.005926 crc=ff 30 MOhm 2W/4W
0000b7 49 49 49 48 44 45 42 4d 4c 41 41 4b 46 >IIIHDEBMLAAKF< 14: offset=999845 raw_gain=2dc11 gain=1.016611 crc=ff 300 mA DC
0000c4 49 49 49 49 48 43 42 4c 44 42 43 4b 49 >IIIIHCBLDBCKI< 15: offset=999983 raw_gain=2c423 gain=1.016423 crc=ff 3A DC
0000d1 40 40 40 40 40 40 40 40 40 40 40 40 40 >@@@@@@@@@@@@@< 16: offset=000000 raw_gain=00000 gain=1.000000 crc=00 <not used>
0000de 49 49 47 49 43 42 42 40 43 40 42 4d 41 >IIGICBB@C@BMA< 17: offset=997932 raw_gain=20302 gain=1.020302 crc=ff 300 mA/3A AC
0000eb 40 40 40 40 40 40 40 40 40 40 40 40 40 >@@@@@@@@@@@@@< 18: offset=000000 raw_gain=00000 gain=1.000000 crc=00 <not used>
0000f8 40 40 40 40 40 40 40 40 >@@@@@@@@< 19: <padding>
@@@@@FGAM@NOLG@@
@@@GAMMONL@@@@@@
AAMMMNLHIIIIIDAL
DBBKIIIIIIIALDOC
JF@@@@@@@@@@@@@I
IH@CHAAABCMBIIIH
HH@EALAKIIIIIHH@
EMEDK@IIIIII@EMC
MJGIIIIIH@EOAOJF
IIIIII@EOB@KCIII
IIH@ENCAKCIIIIIH
ALOCLIOIIIHDEBML
AAKFIIIIHCBLDBCK
I@@@@@@@@@@@@@II
GICBB@C@BMA@@@@@
@@@@@@@@@@@@@@@@
hp3478a_utils/hp3478util -a calibration_data/hp3478_cal_dump_1.bin -t
************ hp3478util, (c) 2018-2020 fenugrec ************
entry 0x00: OK (30 mV DC)
entry 0x01: OK (300 mV DC)
entry 0x02: OK (3 V DC)
entry 0x03: OK (30 V DC)
entry 0x04: OK (300 V DC)
entry 0x05 ((Not used)): bad cks (0x00) (unused entry)
entry 0x06: OK (ACV)
entry 0x07: OK (30 Ohm 2W/4W)
entry 0x08: OK (300 Ohm 2W/4W)
entry 0x09: OK (3 KOhm 2W/4W)
entry 0x0A: OK (30 KOhm 2W/4W)
entry 0x0B: OK (300 KOhm 2W/4W)
entry 0x0C: OK (3 MOhm 2W/4W)
entry 0x0D: OK (30 MOhm 2W/4W)
entry 0x0E: OK (300 mA DC)
entry 0x0F: OK (3A DC)
entry 0x10 ((Not used)): bad cks (0x00) (unused entry)
entry 0x11: OK (300 mA/3A AC)
entry 0x12 ((Not used)): bad cks (0x00) (unused entry)
hp3478a_utils/hp3478util -a calibration_data/hp3478_cal_dump_1.bin -d
************ hp3478util, (c) 2018-2020 fenugrec ************
entry # offset (rawgain) gain range
00 000067 1D0EF 1.006979 30 mV DC
01 000007 1DDFE 1.006688 300 mV DC
02 000001 1DDDE 1.006668 3 V DC
03 999994 1C422 1.006422 30 V DC
04 999999 1C4F3 1.006393 300 V DC
05 000000 00000 1.000000 (Not used)
06 998038 11123 1.011123 ACV
07 999888 051C1 1.005061 30 Ohm 2W/4W
08 999988 05D54 1.004754 300 Ohm 2W/4W
09 999999 05D3D 1.004727 3 KOhm 2W/4W
0A 999998 05F1F 1.004909 30 KOhm 2W/4W
0B 999999 05F20 1.004920 300 KOhm 2W/4W
0C 999998 05E31 1.004831 3 MOhm 2W/4W
0D 999998 1CF3C 1.005926 30 MOhm 2W/4W
0E 999845 2DC11 1.016611 300 mA DC
0F 999983 2C423 1.016423 3A DC
10 000000 00000 1.000000 (Not used)
11 997932 20302 1.020302 300 mA/3A AC
12 000000 00000 1.000000 (Not used)
Hi,
...snip...
I now get the gain values you have in your post. I'm not sure why my initial data extracted with "-d" was wrong. I wrote the getcal.py in steps and maybe I had some CR/LF in it while debugging, causing the errors.
#!/bin/sh
if [ -f "$1" ]; then
cat "$1" | od -A x -t x1z -w13 --skip=1 | awk 'BEGIN{
SEP="|";
rectypestr="30 mV DC" SEP "300 mV DC" SEP "3 V DC" SEP "30 V DC" SEP "300 V DC" SEP "<not used>" SEP "AC V" SEP "30 Ohm 2W/4W" SEP "300 Ohm 2W/4W" SEP "3 kOhm 2W/4W" SEP "30 kOhm 2W/4W" SEP "300 kOhm 2W/4W" SEP "3 MOhm 2W/4W" SEP "30 MOhm 2W/4W" SEP "300 mA DC" SEP "3A DC" SEP "<not used>" SEP "300 mA/3A AC" SEP "<not used>" SEP "<padding>";
rectype[0] = "";
split(rectypestr, rectype, SEP);
}{
if(NF==15) {
crc=0; oset = ""; gain = ""; cgain = 1.0; multi = 0.01;
for(i=1; i<NF; i++) {
if(length($i)==2) {
crc += strtonum("0x"(substr($i,2))""((i==13)?"0":""));
if (i < 8) { /* first 6 bytes */
oset = oset "" substr($i,2);
} else if (i < 13) { /* next 5 bytes */
gain = gain "" substr($i,2);
digit = strtonum("0x"(substr($i,2)));
cgain += (digit - ((digit > 7) ? 16 : 0)) * multi;
multi = multi / 10;
}
}
}
coset = strtonum(oset); /* raw offset is in bcd; not hex */
if (strtonum(oset)>499999) coset -= 1000000; /* if raw offset is greater than 499999 then its a negative number */
printf "%s\t%.2d: raw_offset=%s raw_gain=%s offset=%+07d gain=%1.6f crc=%.2x %s\n", $0, (NR-1), oset, gain, coset, cgain, crc, rectype[NR];
} else if(NF>1) {
printf "%s\t%.2d: %s\n", $0, (NR-1), rectype[NR];
}
}'
else
echo "$0 <cal file>"
fi
$ ./verify.sh cbueche2.cal
000001 40 40 40 40 46 47 41 4d 40 4e 4f 4c 47 >@@@@FGAM@NOLG< 00: raw_offset=000067 raw_gain=1d0ef offset=+000055 gain=1.006979 crc=ff 30 mV DC
00000e 40 40 40 40 40 47 41 4d 4d 4f 4e 4c 40 >@@@@@GAMMONL@< 01: raw_offset=000007 raw_gain=1ddfe offset=+000007 gain=1.006688 crc=ff 300 mV DC
00001b 40 40 40 40 40 41 41 4d 4d 4d 4e 4c 48 >@@@@@AAMMMNLH< 02: raw_offset=000001 raw_gain=1ddde offset=+000001 gain=1.006668 crc=ff 3 V DC
000028 49 49 49 49 49 44 41 4c 44 42 42 4b 49 >IIIIIDALDBBKI< 03: raw_offset=999994 raw_gain=1c422 offset=-000006 gain=1.006422 crc=ff 30 V DC
000035 49 49 49 49 49 49 41 4c 44 4f 43 4a 46 >IIIIIIALDOCJF< 04: raw_offset=999999 raw_gain=1c4f3 offset=-000001 gain=1.006393 crc=ff 300 V DC
000042 40 40 40 40 40 40 40 40 40 40 40 40 40 >@@@@@@@@@@@@@< 05: raw_offset=000000 raw_gain=00000 offset=+000000 gain=1.000000 crc=00 <not used>
00004f 49 49 48 40 43 48 41 41 41 42 43 4d 42 >IIH@CHAAABCMB< 06: raw_offset=998038 raw_gain=11123 offset=-001962 gain=1.011123 crc=ff AC V
00005c 49 49 49 48 48 48 40 45 41 4c 41 4b 49 >IIIHHH@EALAKI< 07: raw_offset=999888 raw_gain=051c1 offset=-000112 gain=1.005061 crc=ff 30 Ohm 2W/4W
000069 49 49 49 49 48 48 40 45 4d 45 44 4b 40 >IIIIHH@EMEDK@< 08: raw_offset=999988 raw_gain=05d54 offset=-000012 gain=1.004754 crc=ff 300 Ohm 2W/4W
000076 49 49 49 49 49 49 40 45 4d 43 4d 4a 47 >IIIIII@EMCMJG< 09: raw_offset=999999 raw_gain=05d3d offset=-000001 gain=1.004727 crc=ff 3 kOhm 2W/4W
000083 49 49 49 49 49 48 40 45 4f 41 4f 4a 46 >IIIIIH@EOAOJF< 10: raw_offset=999998 raw_gain=05f1f offset=-000002 gain=1.004909 crc=ff 30 kOhm 2W/4W
000090 49 49 49 49 49 49 40 45 4f 42 40 4b 43 >IIIIII@EOB@KC< 11: raw_offset=999999 raw_gain=05f20 offset=-000001 gain=1.004920 crc=ff 300 kOhm 2W/4W
00009d 49 49 49 49 49 48 40 45 4e 43 41 4b 43 >IIIIIH@ENCAKC< 12: raw_offset=999998 raw_gain=05e31 offset=-000002 gain=1.004831 crc=ff 3 MOhm 2W/4W
0000aa 49 49 49 49 49 48 41 4c 4f 43 4c 49 4f >IIIIIHALOCLIO< 13: raw_offset=999998 raw_gain=1cf3c offset=-000002 gain=1.005926 crc=ff 30 MOhm 2W/4W
0000b7 49 49 49 48 44 45 42 4d 4c 41 41 4b 46 >IIIHDEBMLAAKF< 14: raw_offset=999845 raw_gain=2dc11 offset=-000155 gain=1.016611 crc=ff 300 mA DC
0000c4 49 49 49 49 48 43 42 4c 44 42 43 4b 49 >IIIIHCBLDBCKI< 15: raw_offset=999983 raw_gain=2c423 offset=-000017 gain=1.016423 crc=ff 3A DC
0000d1 40 40 40 40 40 40 40 40 40 40 40 40 40 >@@@@@@@@@@@@@< 16: raw_offset=000000 raw_gain=00000 offset=+000000 gain=1.000000 crc=00 <not used>
0000de 49 49 47 49 43 42 42 40 43 40 42 4d 41 >IIGICBB@C@BMA< 17: raw_offset=997932 raw_gain=20302 offset=-002068 gain=1.020302 crc=ff 300 mA/3A AC
0000eb 40 40 40 40 40 40 40 40 40 40 40 40 40 >@@@@@@@@@@@@@< 18: raw_offset=000000 raw_gain=00000 offset=+000000 gain=1.000000 crc=00 <not used>
0000f8 40 40 40 40 40 40 40 40 >@@@@@@@@< 19: <padding>
Specifically, the -d switch forgets to remove the end-of-line line-feed character (0x0A) before processing the line.
Specifically, the -d switch forgets to remove the end-of-line line-feed character (0x0A) before processing the line.
Hi, I got the notification on github concerning this issue, but I can't access my code and crap so I have nothing to suggest until I get back in ~2 weeks. Ping me again if you don't hear from me by then.
But if it's just a processing issue it should be trivial to patch in the meantime (I think we got the math part mostly perfect ? except maybe clamping the gain digits to [-4..+5] , I forget the details)
#!/bin/env python3
# usage : python ./putcal.py calibration_data/hp3478_cal_dump_1.bin
import sys
import pyvisa
rm = pyvisa.ResourceManager()
dvm = rm.open_resource('GPIB::16::INSTR')
calfile = sys.argv[1]
with open(calfile, 'r') as file:
data = file.read().replace('\n', '')
ldata = len(data)
print("got {} bytes from {}".format(ldata, calfile))
if ldata != 256:
print("input file must be 256 bytes after filering newline chars. Now {} bytes, exit".format(ldata))
sys.exit(1)
for addr in range(256):
dval = data[addr]
print("writing position {} with value {}".format(addr, dval))
dvm.write_raw(bytes([ord('X'), addr]))
dvm.write_raw(dval)
dvm.close()
rm.close()
Hi all,
Sorry for the likely necrobump here, but I managed to back up the calibration data of my HP-3478A mostly using the info from this thread! So big thanks!
And here's the cal data <tried but failed to get this into mono-spaced font>:
[jan@rush ~]$ hexdump pa3gyf-hp3478a-01.cal
0000000 4040 4040 4842 4140 4543 4440 484e 4040
0000010 4040 4742 4341 4f45 4d4e 4040 4040 4040
0000020 4142 4443 4045 404f 4949 4949 4549 4341
0000030 4544 4b45 494b 4949 4949 4149 4443 4c41
0000040 444b 4040 4040 4040 4040 4040 4f40 404f
0000050 4040 4543 4143 4d41 4542 4e4d 4949 4849
0000060 4349 4c41 4c43 4a4c 4948 4949 4849 4149
0000070 424c 4d4f 4f49 4949 4949 4949 4c41 4441
0000080 4a4c 494b 4949 4949 4148 4f4c 4540 494a
0000090 4949 4949 4949 4c41 4e40 4a42 494c 4949
00000a0 4949 4148 4f4c 4540 494a 4949 4949 4849
00000b0 4540 4145 4b44 404b 4040 4341 4240 4545
00000c0 454d 4d4d 4040 4040 4341 4542 4e42 4e41
00000d0 4043 4040 4040 4040 4040 4040 4f4f 4040
00000e0 4340 4345 4342 444c 4d43 404c 4040 4040
00000f0 4040 4040 4040 4f4f 4040 4040 4040 4040
0000100
73,
Jan -pa3gyf
It would be nice if someone could write a python or some other multi-platform method that implements the above in a friendly way. There's a lot 3478A's out there. It would make battery replacement a lot less stressful if you could back up the SRAM first and then restore it when done. No more isolated soldering irons, etc. Or even better, it would be good to make a backup *before* the battery goes dead.
I'm attaching a little Python script that pulls the SRAM values out and drops them to stdout. Use like this:
python cal-3478a devicename > mycal
This depends on a properly working linux-gpib setup, and devicename must be a properly configured device in /etc/gpib.conf. No multi-platform GPIB out there, as far as I know.
Thanks so much for working this out -- would hate for my 3478A to die on me. At least now I have a backup! The battery seems to be doing OK, so perhaps I don't need to replace it yet?
root@raspi3:~# sudo dmesg | grep -i -e gpib -e agilent
[ 14.478470] usb 1-1.4: Manufacturer: Agilent Technologies, Inc.
[ 14.648728] gpib_common: loading out-of-tree module taints kernel.
[ 14.661207] Linux-GPIB 4.3.5 Driver
[ 14.746457] agilent_82357a_gpib driver loading
[ 14.748089] usbcore: registered new interface driver agilent_82357a_gpib
[ 14.748122] gpib: registered agilent_82357a interface
[ 15.860168] usb 1-1.4: bus 1 dev num 7 attached to gpib minor 0, agilent usb interface 0
[ 15.871055] agilent_82357a_attach: attached
[ 147.005668] gpib0: exiting autospoll thread
[ 147.006044] agilent_82357a_detach: detached
[ 147.006246] usb 1-1.4: bus 1 dev num 7 attached to gpib minor 0, agilent usb interface 0
[ 147.017505] agilent_82357a_attach: attached
root@raspi3:~#
For those familiar with the 3478A, recall that the cal SRAM is 256 x 4 (NEC UDP5101L or equivalent).
Is that CalRam used as "normal ram too ????"
The first 128 bytes matches across platforms .. aka on all 4 files.
The last 128 bytes matches if compared with the "other backup" taken on the same platform.
But NOT if comparing a Win vs Lin backup
Hmmm ... :palm: - From first post in this threadCode: [Select]For those familiar with the 3478A, recall that the cal SRAM is 256 x 4 (NEC UDP5101L or equivalent).
So what is returned on that "GPIB Read" ... a Nibble (All 256 counts) or a Byte (HP does some magic , and presents those nibbles as bytes)
/Bingo
$ ./verify.sh bingo.cal
000001 40 40 40 44 48 44 42 4f 4c 4c 44 4c 42 >@@@DHDBOLLDLB< 00: raw_offset=000484 raw_gain=2fcc4 offset=+000484 gain=1.018564 crc=ff 30 mV DC
00000e 40 40 40 40 44 45 42 4f 4e 45 4d 4c 45 >@@@@DEBONEMLE< 01: raw_offset=000045 raw_gain=2fe5d offset=+000037 gain=1.018847 crc=ff 300 mV DC
00001b 40 40 40 40 40 44 42 4e 43 45 45 4d 4e >@@@@@DBNCEEMN< 02: raw_offset=000004 raw_gain=2e355 offset=+000004 gain=1.018355 crc=ff 3 V DC
000028 49 49 49 49 49 46 42 4e 41 40 43 4b 48 >IIIIIFBNA@CKH< 03: raw_offset=999996 raw_gain=2e103 offset=-000004 gain=1.018103 crc=ff 30 V DC
000035 40 40 40 40 40 40 42 4d 45 44 44 4e 43 >@@@@@@BMEDDNC< 04: raw_offset=000000 raw_gain=2d544 offset=+000000 gain=1.017544 crc=ff 300 V DC
000042 40 40 40 40 40 40 40 40 40 40 40 40 40 >@@@@@@@@@@@@@< 05: raw_offset=000000 raw_gain=00000 offset=+000000 gain=1.000000 crc=00 <not used>
00004f 49 49 49 43 41 40 41 44 44 4d 4d 4b 4d >IIICA@ADDMMKM< 06: raw_offset=999310 raw_gain=144dd offset=-000690 gain=1.014367 crc=ff AC V
00005c 49 49 49 48 43 41 40 45 44 45 43 4c 47 >IIIHCA@EDECLG< 07: raw_offset=999831 raw_gain=05453 offset=-000169 gain=1.005453 crc=ff 30 Ohm 2W/4W
000069 49 49 49 49 48 42 41 4c 4e 40 4e 4a 48 >IIIIHBALN@NJH< 08: raw_offset=999982 raw_gain=1ce0e offset=-000018 gain=1.005798 crc=ff 300 Ohm 2W/4W
000076 49 49 49 49 49 49 40 45 42 41 40 4c 41 >IIIIII@EBA@LA< 09: raw_offset=999999 raw_gain=05210 offset=-000001 gain=1.005210 crc=ff 3 kOhm 2W/4W
000083 49 49 49 49 49 49 40 45 40 43 44 4b 4d >IIIIII@E@CDKM< 10: raw_offset=999999 raw_gain=05034 offset=-000001 gain=1.005034 crc=ff 30 kOhm 2W/4W
000090 49 49 49 49 49 48 40 45 4f 41 4c 4a 49 >IIIIIH@EOALJI< 11: raw_offset=999998 raw_gain=05f1c offset=-000002 gain=1.004906 crc=ff 300 kOhm 2W/4W
00009d 49 49 49 49 49 48 40 45 4f 45 45 4a 4c >IIIIIH@EOEEJL< 12: raw_offset=999998 raw_gain=05f55 offset=-000002 gain=1.004955 crc=ff 3 MOhm 2W/4W
0000aa 49 49 49 49 49 48 41 4c 44 41 4c 4a 4c >IIIIIHALDALJL< 13: raw_offset=999998 raw_gain=1c41c offset=-000002 gain=1.006406 crc=ff 30 MOhm 2W/4W
0000b7 40 40 40 41 44 47 43 4e 4d 42 40 4d 43 >@@@ADGCNMB@MC< 14: raw_offset=000147 raw_gain=3ed20 offset=+000103 gain=1.027720 crc=ff 300 mA DC
0000c4 40 40 40 40 41 45 43 4e 4e 4e 4c 4c 40 >@@@@AECNNNLL@< 15: raw_offset=000015 raw_gain=3eeec offset=+000013 gain=1.027776 crc=ff 3A DC
0000d1 40 40 40 40 40 40 40 40 40 40 40 40 40 >@@@@@@@@@@@@@< 16: raw_offset=000000 raw_gain=00000 offset=+000000 gain=1.000000 crc=00 <not used>
0000de 49 49 49 41 45 45 42 44 43 41 43 4c 4c >IIIAEEBDCACLL< 17: raw_offset=999155 raw_gain=24313 offset=-000845 gain=1.024313 crc=ff 300 mA/3A AC
0000eb 40 40 40 40 40 40 40 40 40 40 40 40 40 >@@@@@@@@@@@@@< 18: raw_offset=000000 raw_gain=00000 offset=+000000 gain=1.000000 crc=00 <not used>
0000f8 40 40 40 40 40 40 40 40 0a >@@@@@@@@.< 19: <padding>
See my verify.sh script on post #123 on the previous page.
Is that CalRam used as "normal ram too ????"
Since the upper nibble doesn't exist on the bus, the MCU may just assign a fixed hex 4 to that so the byte is a valid ASCII (between '@' and 'O').
anl p2,#0xf7 ; 14c3 - 9a f7 .w ; calRAM_CE
mov a,r6 ; 14c5 - fe ~
mov r0,a ; 14c6 - a8 (
movx a,@r0 ; 14c7 - 80 . ; read CAL!
anl a,#0xf ; 14c8 - 53 0f S.
add a,#0x40 ; 14ca - 03 40 .@
#
# Watch out !!!
# Python3 is doing "locale/character set" conversion on strings
# You will be BITTEN, if you use old Python2 strings
#
# Force a binary array by creating w. bytearray
bytesArr = bytearray(b'\x00\x00\x00')
gpib.timeout(devhdl, gpib.T1s)
for addr in range(256):
bytesArr[0] = ord('W')
bytesArr[1] = addr
bytesArr[2] = 10 # LF
# The two below lines will NOT work due to the new locale conversion stuff.
#cmd = "W" + chr(addr) + '\n'
#gpib.write(devhdl, cmd)
gpib.write(devhdl, bytes(bytesArr)) # Convert bytesArr back to bytes, before using it
val = gpib.read(devhdl, 1)
sys.stdout.buffer.write(val)
* On lnux link with -lm : gcc -o hp3478util hp3478util.c -lm
* And - #define WITH_GPIB 0
Raspi$ ./hp3478util -d -b hp3478a-cal-raspi3-2022022501.cal
************ hp3478util, (c) 2018-2020 fenugrec ************
entry # offset (rawgain) gain range
00 000484 2FCC4 1.018564 30 mV DC
01 000045 2FE5D 1.018847 300 mV DC
02 000004 2E355 1.018355 3 V DC
03 999996 2E103 1.018103 30 V DC
04 000000 2D544 1.017544 300 V DC
05 000000 00000 1.000000 (Not used)
06 999310 144DD 1.014367 ACV
07 999831 05453 1.005453 30 Ohm 2W/4W
08 999982 1CE0E 1.005798 300 Ohm 2W/4W
09 999999 05210 1.005210 3 KOhm 2W/4W
0A 999999 05034 1.005034 30 KOhm 2W/4W
0B 999998 05F1C 1.004906 300 KOhm 2W/4W
0C 999998 05F55 1.004955 3 MOhm 2W/4W
0D 999998 1C41C 1.006406 30 MOhm 2W/4W
0E 000147 3ED20 1.027720 300 mA DC
0F 000015 3EEEC 1.027776 3A DC
10 000000 00000 1.000000 (Not used)
11 999155 24313 1.024313 300 mA/3A AC
12 000000 00000 1.000000 (Not used)
Raspi$ ./hp3478util -t -b hp3478a-cal-raspi3-2022022501.cal
************ hp3478util, (c) 2018-2020 fenugrec ************
entry 0x00: OK (30 mV DC)
entry 0x01: OK (300 mV DC)
entry 0x02: OK (3 V DC)
entry 0x03: OK (30 V DC)
entry 0x04: OK (300 V DC)
entry 0x05 ((Not used)): bad cks (0x00) (unused entry)
entry 0x06: OK (ACV)
entry 0x07: OK (30 Ohm 2W/4W)
entry 0x08: OK (300 Ohm 2W/4W)
entry 0x09: OK (3 KOhm 2W/4W)
entry 0x0A: OK (30 KOhm 2W/4W)
entry 0x0B: OK (300 KOhm 2W/4W)
entry 0x0C: OK (3 MOhm 2W/4W)
entry 0x0D: OK (30 MOhm 2W/4W)
entry 0x0E: OK (300 mA DC)
entry 0x0F: OK (3A DC)
entry 0x10 ((Not used)): bad cks (0x00) (unused entry)
entry 0x11: OK (300 mA/3A AC)
entry 0x12 ((Not used)): bad cks (0x00) (unused entry)
david@I7MINT:~/Github/hp3478a_utils$ ./hp3478util -a djrm-cal.txt -t
************ hp3478util, (c) 2018-2020 fenugrec ************
entry 0x00 (30 mV DC): bad cks (0xFE)
entry 0x01: OK (300 mV DC)
entry 0x02 (3 V DC): bad cks (0x0C)
entry 0x03: OK (30 V DC)
entry 0x04: OK (300 V DC)
entry 0x05: OK ((Not used))
entry 0x06: OK (ACV)
entry 0x07: OK (30 Ohm 2W/4W)
entry 0x08: OK (300 Ohm 2W/4W)
entry 0x09: OK (3 KOhm 2W/4W)
entry 0x0A: OK (30 KOhm 2W/4W)
entry 0x0B: OK (300 KOhm 2W/4W)
entry 0x0C: OK (3 MOhm 2W/4W)
entry 0x0D: OK (30 MOhm 2W/4W)
entry 0x0E: OK (300 mA DC)
entry 0x0F: OK (3A DC)
entry 0x10: OK ((Not used))
entry 0x11: OK (300 mA/3A AC)
entry 0x12: OK ((Not used))
entry 0x00: OK (30 mV DC)
entry 0x01: OK (300 mV DC)
entry 0x02: OK (3 V DC)
entry 0x03: OK (30 V DC)
entry 0x04: OK (300 V DC)
entry 0x05: OK ((Not used))
entry 0x06: OK (ACV)
entry 0x07: OK (30 Ohm 2W/4W)
entry 0x08: OK (300 Ohm 2W/4W)
entry 0x09: OK (3 KOhm 2W/4W)
entry 0x0A: OK (30 KOhm 2W/4W)
entry 0x0B: OK (300 KOhm 2W/4W)
entry 0x0C: OK (3 MOhm 2W/4W)
entry 0x0D: OK (30 MOhm 2W/4W)
entry 0x0E: OK (300 mA DC)
entry 0x0F: OK (3A DC)
entry 0x10: OK ((Not used))
entry 0x11: OK (300 mA/3A AC)
entry 0x12: OK ((Not used))
david@I7MINT:~/Github/hp3478a_utils$ ./hp3478util -a djrm-cal2.txt -d
************ hp3478util, (c) 2018-2020 fenugrec ************
entry # offset (rawgain) gain range
00 000293 14CD5 1.013575 30 mV DC
01 000029 14C1C 1.013606 300 mV DC
02 000000 13310 1.013310 3 V DC
03 999995 14F33 1.013933 30 V DC
04 000000 14C4E 1.013638 300 V DC
05 000000 00000 1.000000 (Not used)
06 998908 15D35 1.014735 ACV
07 999603 1CE3F 1.005829 30 Ohm 2W/4W
08 999958 1CE21 1.005821 300 Ohm 2W/4W
09 999995 05524 1.005524 3 KOhm 2W/4W
0A 999995 05220 1.005220 30 KOhm 2W/4W
0B 999996 05125 1.005125 300 KOhm 2W/4W
0C 999996 053C0 1.005260 3 MOhm 2W/4W
0D 999996 1CFF1 1.005891 30 MOhm 2W/4W
0E 999974 24052 1.024052 300 mA DC
0F 999997 240FF 1.023989 3A DC
10 000000 00000 1.000000 (Not used)
11 998908 24FCE 1.023858 300 mA/3A AC
12 000000 00000 1.000000 (Not used)
.I may need tinkering with pull-up resistors and speed settings, maybe the supply voltage.Hi & Thanks for answering,
Getting the error always at the same position is indeed a bit odd.In normal use I'm getting no errors, commands are returned without any visible errors.
Are other tranfers (e.g. repeated status / version reading) also getting occasional tranfer errors ?
...
It can be worth looking at the signal levels with a scope.
... I tried sending 'W' 0x00 CRLF to see if I could get an individual byte back but never received anything at all.
Creating a bash script to automate calling 256 echo lines above or scraping the first character from the log file is left as an exercise for the diligent student.
@@@BICADLMELM : CkSum = (205 + 49) Checksum Fail.
@@@@BIADLALMF : CkSum = (214 + 41) Checksum OK.
M@@@@@ACCA@OG : CkSum = (247 + 21) Checksum Fail.
@+00.0007E-3
@+00.0007E-3
@+00.0005E-3
@+00.0004E-3
B+00.0004E-3
I+00.0007E-3
C+00.0007E-3
A+00.0004E-3
D+00.0004E-3
L+00.0006E-3
M+00.0004E-3
E+00.0007E-3
L+00.0009E-3
M+00.0009E-3
@+00.0008E-3
@+00.0013E-3
GPIB
@+00.0010E-3
@+00.0007E-3
B+00.0007E-3
I+00.0008E-3
A+00.0006E-3
D+00.0005E-3
L+00.0010E-3
A+00.0011E-3
L+00.0012E-3
M+00.0011E-3
F+00.0007E-3
M+00.0008E-3
@+00.0009E-3
@+00.0009E-3
@+00.0009E-3
@+00.0010E-3
GPIB
@+00.0011E-3
A+00.0008E-3
C+00.0005E-3
C+00.0010E-3
A+00.0009E-3
@+00.0011E-3
O+00.0009E-3
G+00.0008E-3
with ++ver every 16 bytes... I wonder if this is a true copy of what I have in the cal. I would expect the meter to show an error though.
...Oooh... Back to basics. There's always a risk poking at something that's working, but you can minimize the risk by not putting your probes directly on the RAM chip. Probe the data and address lines, /RD, and the memory enable /OE1 on other chips, such as the processor and U506. Also stay away from U515 since it is also powered by the battery when the unit is off (it holds the RAM write line high), and obviously leave the CAL switch off.
I'm tempted to fit the LA onto the ram pins but I'm afraid I'd mess up and lose the cal completely.
If I had full confidence in the GPIB cal reading then I'd try cal writing good checksums into the device (but I won't)That's a wise choice.
If you haven't seen it, here's some detail on how the SRAM readout was done previously:
I'm afraid I'd mess up and lose the cal completely.Well clearly, not *completely* - only those two ranges with questionable content. You could test writing and reading back values to the unused rows, that should be fairly harmless (unless writing somehow fails due to a bad RAM and you can't restore it, in which case you'd be hosed anyway).
diff showing checksum correction, found by guesswork!If we're going to go that way, I'll add my own guesses :
You may want to try a different AR488 firmware version and see if this fixes your problem.
I recently had users of my software getting checksum errors when they tried to read the meter calibration. I found that this was caused by problems with specific AR488 firmware versions. My program works with AR488 0.49.14 but fails with AR488 0.51.18.
Version 12-29-22
Gain encode/decode algorithm thanks to: Steve1515 (EEVblog) and fenugrec (EEVblog).
Windows XP Service Pack 3 Platform ID 2
Config file loaded.
Arduino COM delay 1100ms
Debug ON.
Command delay = 0ms.
Max COM port = 64.
OC:Open COM33 CheckCom.
CheckCom start COM33
CheckCom end CreateFileA COM33
CheckCom port found
CheckCom end CloseHandle COM33
OC:Open COM33 open port.
OC:Open COM33 OK.
CA:Start CheckAdapter on COM33
CA:Check Prologix GPIB adapter. ProVer =:"GPIB"
QS: Send:"++ver" Reply:""
CA:Prologix not found. ++ver retry for Arduino.
CA:Retry ++ver (Arduino boot delay)
-r CA:Retry: Found Prologix adapter (Arduino retry).
CA:Exit checkAdapter on COM33
COM port set to COM33
IG:Start InitGPIB
IG:Find Prologix GPIB adapter.
IG:ProVer srch:"GPIB"
IG:Found Prologix adapter.
IG:set ++mode 1.
IG:set eot_enable 0.
IG:set read timeout:++read_tmo_ms 3000
IG:SetGPIB Address ++addr 23 success.
IG:set EOI 0.
IG:set EOS 0.
IG:Set auto talk mode off: ++auto 0 success.
IGT:QSB result 1
Instrument address set to GPIB 23
3478A using current instrument settings.
3478A connected.
Instrument start
Instrument stop/local
Instrument stop/local
CF:LogPath: Z:\home\david\Downloads\HP3478A\log\:Z:\home\david\Downloads\HP3478A\cfg\
Reading calibration data.
**********
Verify checksums.
@@@BICADLNELM : CkSum = (205 + 50) Checksum OK.
@@@@BIADLALMF : CkSum = (214 + 41) Checksum OK.
@@@@@@ACCA@OG : CkSum = (247 + 8) Checksum OK.
IIIIIEADOCCKC : CkSum = (179 + 76) Checksum OK.
@@@@@@ADLDNML : CkSum = (220 + 35) Checksum OK.
@@@@@@@@@@@OO : CkSum = (255 + 0) Checksum OK.
IIHI@HAEMCEKI : CkSum = (185 + 70) Checksum OK.
IIIF@CALNCOJN : CkSum = (174 + 81) Checksum OK.
IIIIEHALNBAK@ : CkSum = (176 + 79) Checksum OK.
IIIIIE@EEBDKM : CkSum = (189 + 66) Checksum OK.
IIIIIE@EBB@LD : CkSum = (196 + 59) Checksum OK.
IIIIIF@EABEKO : CkSum = (191 + 64) Checksum OK.
IIIIIF@ECL@KH : CkSum = (184 + 71) Checksum OK.
IIIIIFALOOAJ@ : CkSum = (160 + 95) Checksum OK.
IIIIGDBD@EBLC : CkSum = (195 + 60) Checksum OK.
IIIIIGBD@OOJG : CkSum = (167 + 88) Checksum OK.
@@@@@@@@@@@OO : CkSum = (255 + 0) Checksum OK.
IIHI@HBDOLNJE : CkSum = (165 + 90) Checksum OK.
@@@@@@@@@@@OO : CkSum = (255 + 0) Checksum OK.
Reading calibration data complete.
Calibration data checksum valid.
Calibration data saved to:Z:\home\david\Downloads\HP3478A\cfg\HP3478A.cal
david@I7MINT:~/Github/hp3478a_utils$ ./hp3478util
************ hp3478util, (c) 2018-2020 fenugrec ************
some missing args.
usage:
***** file input, if applicable
--ascfile -a <filename> ASCII CAL dump
--binfile -b <filename> binary CAL dump (one byte per nibble)
***** action : specify one
-t test checksums of every record
-p <outfile> create dump with processed bytes (clear 4 higher bits)
-d dump raw data for every record
david@I7MINT:~/Github/hp3478a_utils$ ./hp3478util -a HP3478A.cal -t
************ hp3478util, (c) 2018-2020 fenugrec ************
entry 0x00: OK (30 mV DC)
entry 0x01: OK (300 mV DC)
entry 0x02: OK (3 V DC)
entry 0x03: OK (30 V DC)
entry 0x04: OK (300 V DC)
entry 0x05: OK ((Not used))
entry 0x06: OK (ACV)
entry 0x07: OK (30 Ohm 2W/4W)
entry 0x08: OK (300 Ohm 2W/4W)
entry 0x09: OK (3 KOhm 2W/4W)
entry 0x0A: OK (30 KOhm 2W/4W)
entry 0x0B: OK (300 KOhm 2W/4W)
entry 0x0C: OK (3 MOhm 2W/4W)
entry 0x0D: OK (30 MOhm 2W/4W)
entry 0x0E: OK (300 mA DC)
entry 0x0F: OK (3A DC)
entry 0x10: OK ((Not used))
entry 0x11: OK (300 mA/3A AC)
entry 0x12: OK ((Not used))
david@I7MINT:~/Github/hp3478a_utils$ ./hp3478util -a HP3478A.cal -d
************ hp3478util, (c) 2018-2020 fenugrec ************
entry # offset (rawgain) gain range
00 000293 14CE5 1.013585 30 mV DC
01 000029 14C1C 1.013606 300 mV DC
02 000000 13310 1.013310 3 V DC
03 999995 14F33 1.013933 30 V DC
04 000000 14C4E 1.013638 300 V DC
05 000000 00000 1.000000 (Not used)
06 998908 15D35 1.014735 ACV
07 999603 1CE3F 1.005829 30 Ohm 2W/4W
08 999958 1CE21 1.005821 300 Ohm 2W/4W
09 999995 05524 1.005524 3 KOhm 2W/4W
0A 999995 05220 1.005220 30 KOhm 2W/4W
0B 999996 05125 1.005125 300 KOhm 2W/4W
0C 999996 053C0 1.005260 3 MOhm 2W/4W
0D 999996 1CFF1 1.005891 30 MOhm 2W/4W
0E 999974 24052 1.024052 300 mA DC
0F 999997 240FF 1.023989 3A DC
10 000000 00000 1.000000 (Not used)
11 998908 24FCE 1.023858 300 mA/3A AC
12 000000 00000 1.000000 (Not used)
Here is data from a user of my program that had the same checksum fail. He also had a checksum fail on the first and third cal entries. That might not be a coincedence. .There is a bit of a pattern showing.
AR488 GPIB controller, ver. 0.49.14, 02/03/2021
Reading calibration data.
**********
Verify checksums.
@@@CA@BLLLNLG : CkSum = (199 + 56) Checksum OK.
@@@@CABLLCOLO : CkSum = (207 + 48) Checksum OK.
@@@@@DBLLOELM : CkSum = (205 + 50) Checksum OK.
IIIIIDAEBAOKF : CkSum = (182 + 73) Checksum OK.
@@@@@@AEBMNML : CkSum = (220 + 35) Checksum OK.
@@@@@@@@@@@OO : CkSum = (255 + 0) Checksum OK.
IIIE@BADODEL@ : CkSum = (192 + 63) Checksum OK.
IIII@D@E@MNKG : CkSum = (183 + 72) Checksum OK.
IIIIIA@EDNNJL : CkSum = (172 + 83) Checksum OK.
IIIIII@ECDDKI : CkSum = (185 + 70) Checksum OK.
IIIIII@EABLKE : CkSum = (181 + 74) Checksum OK.
IIIIII@EBBOKA : CkSum = (177 + 78) Checksum OK.
IIIIII@EBMAKD : CkSum = (180 + 75) Checksum OK.
IIIIII@EBDOJO : CkSum = (175 + 80) Checksum OK.
@@@BF@CNOE@MB : CkSum = (210 + 45) Checksum OK.
@@@@BECN@@MMJ : CkSum = (218 + 37) Checksum OK.
@@@@@@@@@@@OO : CkSum = (255 + 0) Checksum OK.
IIIE@BCLCOBKJ : CkSum = (186 + 69) Checksum OK.
@@@@@@@@@@@OO : CkSum = (255 + 0) Checksum OK.
Reading calibration data complete.
Calibration data checksum valid.
Calibration data saved to:D:\HP3478A_6\cfg\HP3478A.cal
#################################################
AR488 GPIB controller, ver. 0.51.18, 26/02/2023
Reading calibration data.
**********
Verify checksums.
@@@CA@BLLGNLG : CkSum = (199 + 51) Checksum Fail.
@@@@CABLLCOLO : CkSum = (207 + 48) Checksum OK.
G@@@@DBLLOELM : CkSum = (205 + 57) Checksum Fail.
IIIIIDAEBAOKF : CkSum = (182 + 73) Checksum OK.
@@@@@@AEBMNML : CkSum = (220 + 35) Checksum OK.
@@@@@@@@@@@OO : CkSum = (255 + 0) Checksum OK.
IIIE@BADODEL@ : CkSum = (192 + 63) Checksum OK.
IIII@D@E@MNKG : CkSum = (183 + 72) Checksum OK.
IIIIIA@EDNNJL : CkSum = (172 + 83) Checksum OK.
IIIIII@ECDDKI : CkSum = (185 + 70) Checksum OK.
IIIIII@EABLKE : CkSum = (181 + 74) Checksum OK.
IIIIII@EBBOKA : CkSum = (177 + 78) Checksum OK.
IIIIII@EBMAKD : CkSum = (180 + 75) Checksum OK.
IIIIII@EBDOJO : CkSum = (175 + 80) Checksum OK.
@@@BF@CNOE@MB : CkSum = (210 + 45) Checksum OK.
@@@@BECN@@MMJ : CkSum = (218 + 37) Checksum OK.
@@@@@@@@@@@OO : CkSum = (255 + 0) Checksum OK.
IIIE@BCLCOBKJ : CkSum = (186 + 69) Checksum OK.
@@@@@@@@@@@OO : CkSum = (255 + 0) Checksum OK.
Reading calibration data complete.
Calibration data not saved. Invalid checksum!
I just tested with my AR488. Checksum fails on first and third entry when using 0.51.18.
(note, I changed device ID back to standard 23 from 18 during investigation)
PS C:\Users\David\Downloads\HP3478ACalibration_20200126> .\HP3478ACalibration.exe -f cal.txt -r 18
Reading calibration data from instrument...
ERROR: Failed while reading calibration data from instrument.
Extended Error Information:
Could not communicate with instrument.
PS C:\Users\David\Downloads\HP3478ACalibration_20200126> .\HP3478ACalibration.exe -f cal.txt -r 18
Reading calibration data from instrument...
ERROR: Failed while reading calibration data from instrument.
Extended Error Information:
Invalid GPIB adapter version string.
David, your observations in #152 are also appreciated. I had noticed however, that in your #136, the wrong character is in position 13. It just so happens that in lmerster's example that the 10th and 13th character are the same but a noteworthy pattern nonetheless.My post #150 has an attachment image showing the bad and good transfers, the data in post #136 has the bad and manually 'corrected' values, I later realised that the error positions were not what I had guessed. clear now? relevant section of image inline below:
I have been trying to refresh my memory on how the dump is generated and found a note that says a W<addr> command is sent to the instrument where <addr> runs from 0 to 255, presumably in a loop. I am assuming that a ++read has to be sent to read each byte in turn? From the dump it would see that a checksum is calculated for every 13 bytes received?
print #main.Terminal,"Reading calibration data."
print #comm,"D2READING CAL" '"READING CAL" message on meter display
call sleep 10 'Fix for "John AR488" Firmware
y=0
for x = 0 to 255 'Read 256 nibbles
cp$=chr$(x)
'<ESC> sequence to send reserved binary chars to Prologix adapter
select case x
case 13 '<CR>
cp$=esc$+cp$
case 10 '<LF>
cp$=esc$+cp$
case 27 '<ESC>
cp$=esc$+cp$
case 43 '"+"
cp$=esc$+cp$
end select
'Read instrument config data. Each char contains one nibble.
ICal$(x)=QuerySERB$("W"+cp$,cr$,1,1)
if len(ICal$(x))<>1 then
if DBug then print #main.Terminal,"RC:Fail query W :";ICal$(x);" Len:";len(ICal$(x))
print #main.Terminal,"Instrument com fail."
if handle$ <> "NoSave" then
notice "Instrument com fail. Calibration not read."
else
notice "Instrument com fail during calibration data backup!"
end if
InstOK=0:goto [CalAbort] 'Instrument com fail
end if
y=y+1:if y>24 then print #main.Terminal,"*";:y=0
next x
'print #main.Terminal,":";ICal$(0);":";asc(ICal$(0)) 'Test for Girlando 0x00 binary send bug
print #main.Terminal,cr$;"Verify checksums."
CRSum=1 'init read data checsum is valid
for x = 0 to 18 'Checksum for 19 cal entries
cs=0 'Checksum
for y= 0 to 10 '11 nibbles data in each entry
nib=asc(ICal$((x*13)+y+1))
nib=nib and 15 'mask hi nibble
print #main.Terminal,ICal$((x*13)+y+1);
cs=cs+nib
cs=cs and 255 'Truncate to 8 bits
next y
dcs=cs
nib=asc(ICal$((x*13)+12))
nib=nib and 15 'mask hi nibble
print #main.Terminal,ICal$((x*13)+12);
nib=nib * 16 'Shift left 4 bits
cs=cs+nib
cs=cs and 255 'Truncate to 8 bits
nibh=nib
nib=asc(ICal$((x*13)+13))
nib=nib and 15 'mask hi nibble
print #main.Terminal,ICal$((x*13)+13);" : CkSum = (";
print #main.Terminal,nib+nibh;" ";
cs=cs+nib
cs=cs and 255 'Truncate to 8 bits
if dcs>10 then 'Format text
print #main.Terminal,"+ ";dcs;") ";
else
print #main.Terminal,"+ ";dcs;") ";
end if
if cs=255 then
print #main.Terminal,"Checksum OK."
else
if x=5 or x=16 or x=18 then
print #main.Terminal,"Checksum fail unused loc-ignore."
else
print #main.Terminal,"Checksum Fail."
CRSum=0 'Checksum fail
end if
end if
next x
print #main.Terminal,cr$;
print #main.Terminal,"Reading calibration data complete."
if CRSum=1 then
print #main.Terminal,"Calibration data checksum valid."
' if handle$<> "NoSave" then '
print #main.Terminal,"Calibration data saved to:";CalFileU$
open CalFileU$ for output as #5
for x = 0 to 255
print #5,ICal$(x);
next x
close #5
' end if
else
if handle$<> "NoSave" then
print #main.Terminal,"Calibration data not saved. Invalid checksum!"
notice "Calibration data not saved. invalid checksum!"
else
print #main.Terminal,"Invalid checksum during calibration data read!"
notice "Invalid checksum during calibration data backup!"
end if
end if
'====================================================
function QuerySERB$(icmd$,irsp$,blen,timeout)
'This function sends a command, then waits for a response or timeout
'Allows blen # of binary chars to be retrieved.
'icmd$ = command to send
'irsp$ = expected response
'blen = binary data flag >0 = number of expected bytes
'timeout = # seconds to abort (ms resolution)
if icmd$<>"" then if lof(#comm) > 0 then rs$ = input$(#comm, lof(#comm)) 'Flush buffer
if icmd$<>"" then print #comm,icmd$ 'Send command if present
if VTD>0 then call sleep VTD 'Time delay for Arduino adapter
' if DBug then print #main.Terminal,"QuerySERB: READ EOI"
if blen>0 then
print #comm,"++read eoi" 'Request response wait for EOI
' if DBug then print #main.Terminal,"QuerySERB:++read eoi"
else
print #comm,"++read eoi"
' in QueryserB Girlando adapter chokes on this:
' just use read eoi for now
' print #comm,"++read ";asc(right$(irsp$,1)) 'Request response no EOI wait for last char in irsp$
' if DBug then print #main.Terminal,"QuerySERB:++read "; asc(right$(irsp$,1));":"
end if
' if DBug then print #main.Terminal,"QuerySERB: READ EOIx"
ok = 0 'Start with error flag set
dl=0 'Binary data length
er$ = "" 'Instrument response
RTimeS=time$("ms") 'Init the timer
while ETime(RTimeS) < (timeout*1000) and ok = 0
if lof(#comm) > 0 then
rs$ = input$(#comm, lof(#comm))
er$ = er$ + rs$
dl=len(er$)
if blen<>0 then
'Use length if length > 0
if dl>=blen then ok=1 'Got all # bytes?
else
'Use ASCII terminator if length = 0
if instr(er$,irsp$) > 0 then ok = 1 'Found terminating string?
end if
RTimeS=time$("ms") 'Init the timer
end if
call sleep 1 'Don't be a CPU hog
wend
' if counter >0 then print #main.Terminal, "RespQS$: ";counter
QuerySERB$=er$ 'Return string
if ok = 0 then QuerySERB$="" 'Return null for error
' if DBug then print #main.Terminal,"QuerySERB Send:";qt$;icmd$;qt$;"QSB Reply:";qt$;er$;qt$;"QSB Delay:";VTD;"ms"
' if DBug then
' for n=1 to len(er$):print #main.Terminal, asc(mid$(er$,n,1));"%";:next
' end if
if lof(#comm) > 0 then er$ = input$(#comm, lof(#comm)) 'Clear any remaining from buffer
end function
select case x
case 13 '<CR>
cp$=esc$+cp$
case 10 '<LF>
cp$=esc$+cp$
case 27 '<ESC>
cp$=esc$+cp$
case 43 '"+"
cp$=esc$+cp$
end select
Does the cal data reading process set ++eoi 1? Could someone run a test reading the cal data with ++eoi 1 set please and post whether they get a successful read or the same result?Greetings,
cmd[0]='W';
cmd[2]='\n';
for (idx=0; idx < CALSIZE; idx++) {
cmd[1] = (uint8_t) idx;
ibwrt(Dev, cmd, 3);
if (ibsta & ERR) {
printf("wrt problem @ 0x%X\n", idx);
goto badexit;
}
ibrd(Dev, &buf[idx], 1);
$ ./verify.sh pqass.cal
...
000035 49 49 49 49 49 49 42 45 43 4e 4d 4a 44 >IIIIIIBECNMJD< 04: raw_offset=999999 raw_gain=253ed offset=-000001 gain=1.025277 crc=ff 300 V DC
...
$ ./verify.sh /tmp/pqass.redo.cal
...
000035 49 49 49 49 49 49 42 45 43 4e 4d 4a 4d >IIIIIIBECNMJM< 04: raw_offset=999999 raw_gain=253ed offset=-000001 gain=1.025277 crc=108 300 V DC
...
void GPIBbus::sendData(char *data, uint8_t dsize) {
...
// Write the data string
for (int i = 0; i < dsize; i++) {
// If EOI asserting is on
if (cfg.eoi) {
// Send all characters
err = writeByte(data[i], NO_EOI);
} else {
// Otherwise ignore non-escaped CR, LF and ESC
if ((data[i] != CR) && (data[i] != LF) && (data[i] != ESC)) err = writeByte(data[i], NO_EOI);
}
#ifdef DEBUG_GPIBbus_SEND
DB_RAW_PRINT(data[i]);
#endif
if (err) break;
}
...
void gpibSendData(char *data, uint8_t dsize) {
...
for (int i = 0; i < dsize; i++) {
// If EOI asserting is on
if (AR488.eoi) {
// Send all characters
err = gpibWriteByte(data[i]);
} else {
// Otherwise ignore non-escaped CR, LF and ESC
if ((data[i] != CR) || (data[i] != LF) || (data[i] != ESC)) err = gpibWriteByte(data[i]);
}
#ifdef DEBUG3
dbSerial->print(data[i]);
#endif
if (err) break;
}
...
if ((data[i] != CR) || (data[i] != LF) || ...
code given that this will always return true.
I see in the console that the hp3478.exe program sends a "++eoi 0" command at startup, If I manually send "++eoi 1" after the program has started from another shell then a subsequent read of the cal setting succeeds.
hth David
// Write the data string
for (int i = 0; i < dsize; i++) {
// If EOI asserting is on
if (AR488.eoi) {
// Send all characters
err = gpibWriteByte(data[i]);
} else {
// Otherwise ignore non-escaped CR, LF and ESC
if ((data[i] != CR) || (data[i] != LF) || (data[i] != ESC)) err = gpibWriteByte(data[i]);
}
if (err) break;
}
if ((data[i] != CR) && (data[i] != LF) && (data[i] != ESC)) state = writeByte(data[i], NO_EOI);
Am I reading correctly that you guys are sending (as seen on GPIB) W \r <addr> \n ?The trace I made shows (#159) W<addr>\r\n but in some cases the <addr> is missed out and the subsequent \r gets interpreted as the address.
On the one hand filtering could be removed so that all characters sent regardless. On the other hand, because we are dealing with bytes rather than ASCII text, ought we to be treating the data as binary and therefore using ++eoi 1? I am open to suggestion and perhaps will need to consider whether the filtering really is necessary.
The question that now arises how to deal with this appropriately. On the one hand filtering could be removed so that all characters sent regardless. On the other hand, because we are dealing with bytes rather than ASCII text, ought we to be treating the data as binary and therefore having the HP3478A set to using EOI only as terminator and the AR488 set with ++eoi 1 and ++eos 3 (no terminator characters)? It looks like the meter ignores the trailing CRLF anyway, so perhaps ++eoi 1 and leaving the meter as is would be sufficient? I am open to suggestion and perhaps will also need to re-consider whether the filtering really is necessary or whether it is more of a hindrance and should be removed.
Having "slept on it" I concur that Prologix compatibility should be maintained as this was the intention from the start. ... Hopefully someone can tell me whether the cal data is now retrieved correctly as it was previously without needing to use ++eoi 1 ?Greetings,
$ ./verify.sh radar.cal
000001 49 49 49 49 49 49 49 49 49 49 49 49 49 >IIIIIIIIIIIII< 00: raw_offset=999999 raw_gain=99999 offset=-000001 gain=0.922223 crc=fc 30 mV DC
00000e 49 49 49 49 49 49 49 49 49 49 49 49 49 >IIIIIIIIIIIII< 01: raw_offset=999999 raw_gain=99999 offset=-000001 gain=0.922223 crc=fc 300 mV DC
00001b 49 49 49 49 49 42 42 44 42 41 4c 4e 48 >IIIIIBBDBALNH< 02: raw_offset=999992 raw_gain=2421c offset=-000008 gain=1.024206 crc=12c 3 V DC
000028 49 49 49 49 49 41 42 45 4d 43 42 4b 48 >IIIIIABEMCBKH< 03: raw_offset=999991 raw_gain=25d32 offset=-000009 gain=1.024732 crc=ff 30 V DC
000035 40 40 40 40 40 40 42 44 44 41 44 4f 40 >@@@@@@BDDADO@< 04: raw_offset=000000 raw_gain=24414 offset=+000000 gain=1.024414 crc=ff 300 V DC
000042 40 40 40 40 40 40 40 40 40 40 40 40 40 >@@@@@@@@@@@@@< 05: raw_offset=000000 raw_gain=00000 offset=+000000 gain=1.000000 crc=00 <not used>
00004f 49 49 47 44 43 46 42 44 41 4c 45 4c 41 >IIGDCFBDALELA< 06: raw_offset=997436 raw_gain=241c5 offset=-002564 gain=1.024065 crc=ff AC V
00005c 49 49 49 44 42 47 41 4c 45 4c 42 4b 47 >IIIDBGALELBKG< 07: raw_offset=999427 raw_gain=1c5c2 offset=-000573 gain=1.006462 crc=ff 30 Ohm 2W/4W
000069 49 49 49 49 48 46 41 4c 4c 42 41 4b 41 >IIIIHFALLBAKA< 08: raw_offset=999986 raw_gain=1cc21 offset=-000014 gain=1.005621 crc=ff 300 Ohm 2W/4W
000076 49 49 49 49 49 45 40 45 43 49 49 49 49 >IIIIIE@ECIIII< 09: raw_offset=999995 raw_gain=05399 offset=-000005 gain=1.005223 crc=e5 3 kOhm 2W/4W
000083 49 49 49 49 49 49 49 49 49 49 49 49 49 >IIIIIIIIIIIII< 10: raw_offset=999999 raw_gain=99999 offset=-000001 gain=0.922223 crc=fc 30 kOhm 2W/4W
000090 49 49 49 49 49 49 49 49 49 49 49 49 49 >IIIIIIIIIIIII< 11: raw_offset=999999 raw_gain=99999 offset=-000001 gain=0.922223 crc=fc 300 kOhm 2W/4W
00009d 49 49 49 49 49 49 49 49 49 49 49 49 49 >IIIIIIIIIIIII< 12: raw_offset=999999 raw_gain=99999 offset=-000001 gain=0.922223 crc=fc 3 MOhm 2W/4W
0000aa 49 49 49 49 49 49 49 49 49 49 49 49 49 >IIIIIIIIIIIII< 13: raw_offset=999999 raw_gain=99999 offset=-000001 gain=0.922223 crc=fc 30 MOhm 2W/4W
0000b7 49 49 49 49 49 49 49 49 49 49 49 49 49 >IIIIIIIIIIIII< 14: raw_offset=999999 raw_gain=99999 offset=-000001 gain=0.922223 crc=fc 300 mA DC
0000c4 49 49 49 49 49 49 49 49 49 49 49 49 49 >IIIIIIIIIIIII< 15: raw_offset=999999 raw_gain=99999 offset=-000001 gain=0.922223 crc=fc 3A DC
0000d1 49 49 49 49 49 49 49 49 49 49 49 49 49 >IIIIIIIIIIIII< 16: raw_offset=999999 raw_gain=99999 offset=-000001 gain=0.922223 crc=fc <not used>
0000de 49 49 49 49 49 49 49 49 49 49 49 49 49 >IIIIIIIIIIIII< 17: raw_offset=999999 raw_gain=99999 offset=-000001 gain=0.922223 crc=fc 300 mA/3A AC
0000eb 49 49 49 49 49 49 49 49 49 49 49 49 49 >IIIIIIIIIIIII< 18: raw_offset=999999 raw_gain=99999 offset=-000001 gain=0.922223 crc=fc <not used>
0000f8 49 49 49 49 49 49 49 49 >IIIIIIII< 19: <padding>
Attached is my verify.sh script (slightly updated from my #123 post; added switch to od command to show duplicate lines). I have a 3478A prototype version (https://www.eevblog.com/forum/testgear/hp-3478a-behavior-on-low-ranges) (at least, I think it's a 3478A, it has no label or serial number).
Test | DMM6500 | HP 3478 | Notes |
30 mV | 29.7 mV | 29.7 mV | Was very noisy |
0.3V | 0.3003 | 0.3003 | Was very noisy |
3V | 3.0028 | 3.0030 | |
30V | 30.0290 | 30.0298 | |
70V | 70.0385 | 70.040 | The max my PSU could do |
100mA | 100.000 | 124.24 | |
1.0A | 1.0005 | 1.244 | |
100k | 99.9872 | 99.980 | Using DMMcheck |
10k | 10.00236 | 10.0014 | Using DMMcheck |
1k | 0.0999626 | 0.99955 | Using DMMcheck |
100 | 100.1650 | 100.155 | Using DMMcheck |
5VDC | 4.99985 | 5.0000 | Using DMMcheck |
5VAC | 4.99918 | 4.9998 | Using DMMcheck |
combined with the fact that the dump reads back the same '0x49' for all offsets < 0x20 that it may be due to the GPIB interface I'm using (0x20 = 32 = first printable char).
@pqpass, thank you for decoding my hex dump.
U502 is a 24-pin ceramic DIP with no window, and no stickers on it. I guess it must be prototype firmware. I don't have an EPROM reader so I can't do a dump. Maybe I should get one...
When comparing against my 6500, here's what I get:
...snip...
I used my bench power supply for the DC voltage tests except the last two, those are from a DMMcheck. The resistance tests are also from the DMMcheck. Looks like the amps ranges are clearly not calibrated, though the DC volts and ohms show very good results. This leads me to think, combined with the fact that the dump reads back the same '0x49' for all offsets < 0x20 that it may be due to the GPIB interface I'm using (0x20 = 32 = first printable char).
There seems to be two 'regimes' for the gains, one for the voltage readings and the other for everything else.
Does this imply that there may be something wrong with the current sense part of the meter, given that it's so far off cal?
$ ./verify.sh radar2.cal
000001 40 40 40 42 42 45 42 45 4f 43 4f 4c 4e >@@@BBEBEOCOLN< 00: raw_offset=000225 raw_gain=25f3f offset=+000149 gain=1.024929 crc=ff 30 mV DC
00000e 40 40 40 40 41 42 42 44 45 41 45 4e 4b >@@@@ABBDEAENK< 01: raw_offset=000012 raw_gain=24515 offset=+000010 gain=1.024515 crc=ff 300 mV DC
00001b 40 40 40 40 40 42 42 44 42 41 4c 4e 48 >@@@@@BBDBALNH< 02: raw_offset=000002 raw_gain=2421c offset=+000002 gain=1.024206 crc=ff 3 V DC
000028 49 49 49 49 49 41 42 45 4d 43 42 4b 48 >IIIIIABEMCBKH< 03: raw_offset=999991 raw_gain=25d32 offset=-000009 gain=1.024732 crc=ff 30 V DC
000035 40 40 40 40 40 40 42 44 44 41 44 4f 40 >@@@@@@BDDADO@< 04: raw_offset=000000 raw_gain=24414 offset=+000000 gain=1.024414 crc=ff 300 V DC
000042 40 40 40 40 40 40 40 40 40 40 40 40 40 >@@@@@@@@@@@@@< 05: raw_offset=000000 raw_gain=00000 offset=+000000 gain=1.000000 crc=00 <not used>
00004f 49 49 47 44 43 46 42 44 41 4c 45 4c 41 >IIGDCFBDALELA< 06: raw_offset=997436 raw_gain=241c5 offset=-002564 gain=1.024065 crc=ff AC V
00005c 49 49 49 44 42 47 41 4c 45 4c 42 4b 47 >IIIDBGALELBKG< 07: raw_offset=999427 raw_gain=1c5c2 offset=-000573 gain=1.006462 crc=ff 30 Ohm 2W/4W
000069 49 49 49 49 48 46 41 4c 4c 42 41 4b 41 >IIIIHFALLBAKA< 08: raw_offset=999986 raw_gain=1cc21 offset=-000014 gain=1.005621 crc=ff 300 Ohm 2W/4W
000076 49 49 49 49 49 45 40 45 43 42 45 4b 4e >IIIIIE@ECBEKN< 09: raw_offset=999995 raw_gain=05325 offset=-000005 gain=1.005325 crc=ff 3 kOhm 2W/4W
000083 40 40 40 40 41 46 40 45 45 42 4f 4d 4d >@@@@AF@EEBOMM< 10: raw_offset=000016 raw_gain=0552f offset=+000014 gain=1.005519 crc=ff 30 kOhm 2W/4W
000090 49 49 49 49 49 47 41 4c 4c 4e 43 4a 41 >IIIIIGALLNCJA< 11: raw_offset=999997 raw_gain=1cce3 offset=-000003 gain=1.005583 crc=ff 300 kOhm 2W/4W
00009d 49 49 49 49 49 45 40 45 45 42 4d 4b 44 >IIIIIE@EEBMKD< 12: raw_offset=999995 raw_gain=0552d offset=-000005 gain=1.005517 crc=ff 3 MOhm 2W/4W
0000aa 49 49 49 49 49 48 41 4d 4d 4e 42 49 4f >IIIIIHAMMNBIO< 13: raw_offset=999998 raw_gain=1dde2 offset=-000002 gain=1.006682 crc=ff 30 MOhm 2W/4W
0000b7 49 49 49 49 43 45 41 4d 43 41 4c 4b 45 >IIIICEAMCALKE< 14: raw_offset=999935 raw_gain=1d31c offset=-000065 gain=1.007306 crc=ff 300 mA DC
0000c4 49 49 49 49 48 49 41 4d 4e 4e 44 49 4c >IIIIHIAMNNDIL< 15: raw_offset=999989 raw_gain=1dee4 offset=-000011 gain=1.006784 crc=ff 3A DC
0000d1 40 40 40 40 40 40 40 40 40 40 40 40 40 >@@@@@@@@@@@@@< 16: raw_offset=000000 raw_gain=00000 offset=+000000 gain=1.000000 crc=00 <not used>
0000de 49 49 47 44 43 46 41 4c 43 44 41 4c 44 >IIGDCFALCDALD< 17: raw_offset=997436 raw_gain=1c341 offset=-002564 gain=1.006341 crc=ff 300 mA/3A AC
0000eb 40 40 40 40 40 40 40 40 40 40 40 40 48 >@@@@@@@@@@@@H< 18: raw_offset=000000 raw_gain=00000 offset=+000000 gain=1.000000 crc=08 <not used>
0000f8 40 40 40 40 40 40 40 40 >@@@@@@@@< 19: <padding>
Attached is my verify.sh script (slightly updated from my #123 post; added switch to od command to show duplicate lines).Very clever script. :-+
raw_offset=000611 offset=+000393
Change:
coset = strtonum(oset);
if (strtonum(oset)>499999) coset -= 1000000;
to:
coset = strtonum("+" oset);
if (coset>499999) coset -= 1000000;
How does the firmware know what position the cal enable switch is in (in the non-prototype version)? It seems like S550 enables the microprocessor's WR signal to get connected to U512's R/W pin. Without any direct connection to the switch input, how does the micro know that U512 is not write-enabled and put up the "ENABLE CAL" message?
HP 3478A calibration data
cadt.de 2024-04-16
cal[0] O
0 @@@ACC A@LDM MJ 255 000133 10C4D 133 1.09637
1 @@@@AD AOALN LO 255 000014 1F1CE 14 1.09058
2 @@@@@B AO@BO ML 255 000002 1F02F 2 1.09019
3 IIIIIC AOMMN IG 255 999993 1FDDE -7 1.08668
4 IIIIII AONAD JF 255 999999 1FE14 -1 1.08814
5 @@@@@@ @@@@@ @@ 0 000000 00000 0 1.00000
6 IIIAIB AO@OC KF 255 999192 1F0F3 -808 1.08993
7 IIIBAH ANDL@ KJ 255 999218 1E4C0 -782 1.08360
8 IIICBE AMCBB LE 255 999325 1D322 -675 1.07322
9 IIIIC@ AMDLD KF 255 999930 1D4C4 -70 1.07364
10 IIIIIC AMOMM IH 255 999993 1DFDD -7 1.06867
11 @@@@@@ ALMEN MB 255 000000 1CD5E 0 1.05748
12 @@@@@@ AMLEL MD 255 000000 1DC5C 0 1.06646
13 @@@@@@ AMNOE LO 255 000000 1DEF5 0 1.06795
14 IIIHCD BMMML J@ 255 999834 2DDDC -166 1.16666
15 IIIIHD BLMND JB 255 999984 2CDE4 -16 1.15684
16 @@@@@@ @@@@@ @@ 0 000000 00000 0 1.00000
17 IIIAIB AO@OC KF 255 999192 1F0F3 -808 1.08993
18 @@@@@@ @@@@@ @@ 0 000000 00000 0 1.00000
cal[248..] @@@@@@@@
Figure 7-G-5 (03478-66501) is the older schematics.Got it - however, the documentation is still a bit confusing since the schematics show the NOR gates as U515, while the text(and my board) references U508. In the schematic, U508 is a hex inverter.
Figure 6-5 (C3478-66501) is the newer one, with 7402.
So your machine has a newer configuration.
What kind of U502 you have?Mine is a 20-pin DIP.
Section 6-25 says that revision D changes it to 28 pin chip.