DIY scan card for Keysight 34970A - Page 1
Forum section: electronics / testgear

author: voltsandjolts
author_rank: Unknown
timestamp: May 11, 2022, 05:37:30 pm
content: I've cobbled together a scan card to fit in the 34970A card slot. It's basically a re-hash of myKeithley 20 channel card.I haven't written the firmware yet and first job is to decode the uart serial protocol, which runs at 187500 baud 9N1.I've searched but can't see any info out there about the command structure.Does anybody have any info on this?...if not I'll dig out the logic analyser, but thought I'd ask first.Edit 19JUN2022:I have attached here the schematic pdf, gerbers, firmware source and altium files.This card seems functional to me but has not been extensively tested, there may be gremlinsSAFETY NOTICE:Your choice of SSR bus relays must withstand the maximum voltage placed on the bus by any card in the DAQ.Perhaps armature relays would be a better choice for the bus relays.You must not exceed manufacturer ratings for the DAQ voltage capabilities (300V IIRC?).This design is openly published in the hope that it is useful for development of your own card(s).This design is not extensively tested and comes with no warranty, express or implied.Edit 27JUL2022:Firmware updated to include relay cycle counters to demonstrate the DAQ commands.They are just in RAM, so start at 0 on every power-up.

author: Kean
author_rank: Unknown
timestamp: May 11, 2022, 06:51:50 pm
content: I don't have any info, but I do have 2 x 34970A and 1 x 34972A, plus 2 each of 34901A/903A/907A. So I'd be happy to assist with verifying any protocol info.One of my 34970As I bought cheaply second hand. It needs some cleanup and a replacement fan, so I'm happy to do "guinea pig" testing with it.

author: strawberry
author_rank: Super Contributor
timestamp: May 11, 2022, 07:08:23 pm
content: dont know if DS75S temp sensor is crucial part for temperature measurement

author: H.O
author_rank: Frequent Contributor
timestamp: May 11, 2022, 07:49:25 pm
content: Same here, no info on the protocol but very interested. I have 2 1/2 34970 and a couple of different modules. Let me know if there's anything I can do to help.

author: voltsandjolts
author_rank: Unknown
timestamp: May 12, 2022, 09:46:34 am
content: Thanks for the offers of help.Quote from: strawberry on May 11, 2022, 07:08:23 pmI'm focused on voltage measurements, don't need thermocouple scanning, but if I get this card running, you could easily adapt it to add a cold junction temperature measurement. The pyhysical cold junction on the 34901A is not that impressive, just a couple of copper planes, but I suppose its adequate given the plastic enclosure/stable conditions in the meter. The Keithley 2001-TSCAN is better with it's copper block.

author: strawberry
author_rank: Super Contributor
timestamp: May 12, 2022, 04:26:17 pm
content: recently got 34970Acould make some PCB layout ,schematics

author: strawberry
author_rank: Super Contributor
timestamp: May 13, 2022, 04:32:23 am
content: https://whatever.sdfa3.org/hp-34970a-data-acquisition-unit-communication-protocol.html

author: voltsandjolts
author_rank: Unknown
timestamp: May 13, 2022, 01:08:41 pm
content: Interesting, thank you.Yes, that protocol for the display panel might be similar or even same as the card slot protocol.

author: Gribo
author_rank: Frequent Contributor
timestamp: May 13, 2022, 01:12:26 pm
content: You might want to check the 34980's breadboard module. Their protocol might be the same.

author: voltsandjolts
author_rank: Unknown
timestamp: May 13, 2022, 02:20:57 pm
content: Quote from: Gribo on May 13, 2022, 01:12:26 pmI think the34959Ais just Keysights way of keeping the protocol proprietary while allowing custom circuitry.It just provides relay control lines etc to custom circuits.

author: H.O
author_rank: Frequent Contributor
timestamp: May 13, 2022, 10:16:04 pm
content: I hooked up the logic analyzer (to a 34901A placed in slot 1) and played around a bit.It looks like the baudrate is indeed 187500 but, to me, it doesn't seem to be 8E1 like with the front panel but a rather weird 9N1.First, manually closing/opening channels:Communication starts with the DAQ sending 0x109 to which the card responds with 0x121:Then the DAQ sends  followed  where:COMMAND =0x1E9 for CLOSE0x1E1 for OPENCHANNEL =0x040-0x049 for channels 1 to 100x080-0x089 for channels 11 to 200x015-0x016 for channels 21 to 22.When the DAQ is in scan-mode things are a slightly different.First the DAQ sends 0x1D9 followed by the channel as per above. Then, after some delay (anything between 15ms and 1500ms depending on channel configuration) the DAQ sends 0x109 to which the card responds with 0x101.Obviously there's more to it than this but hey, it's a start :-)

author: strawberry
author_rank: Super Contributor
timestamp: May 14, 2022, 06:08:01 am
content: boot up sequence, card sends card number and slot number(avoiding slot com conflict)0x109 could be slot number

author: H.O
author_rank: Frequent Contributor
timestamp: May 14, 2022, 12:16:02 pm
content: I captured the bootup sequence with the 34901A in each of the three slots, no other cards:34901A in slot 1 of 34970A:Code:At startup the uC RST-pin and the SRQ-pin is held high for aproximately 50ms.Then, after about 1400ms the following happens:DAQ sends 0x119Card responds 0x101DAQ sends 0x121SRQ-signal goes high for 200ns, low for 16us and then high (where it stays)Card responds 0x121DAQ sends 0x11ADAQ sends 0x11B200ms of silenceDAQ sends 0x169, 0x030, 0x000Card responds 0x1215ms of silenceDAQ sends 0x169, 0x030, 0x000Card responds 0x1218ms of silenceDAQ sends 0x1B9, 0x000, 0x000, 0x000, 0x010170ms of silenceDAQ sends 0x109Card responds 0x120DAQ sends 0x109Card responds 0x120DAQ sends 0x109Card responds 0x120DAQ sends 0x109Card responds 0x120DAQ sends 0x109Card responds 0x12134901A in slot 2 of 34970A:Code:At startup the uC RST-pin and the SRQ-pin is held high for aproximately 50ms.Then, after about 1400ms the following happens:DAQ sends 0x119DAQ sends 0x11ACard responds 0x101DAQ sends 0x122SRQ-signal goes high for 200ns, low for 16us and then high (where it stays)Card responds 0x121DAQ sends 0x11B200ms of silenceDAQ sends 0x16A, 0x030, 0x000Card responds 0x1215ms of silenceDAQ sends 0x16A, 0x030, 0x000Card responds 0x1218ms of silenceDAQ sends 0x1BA, 0x000, 0x000, 0x000, 0x010170ms of silenceDAQ sends 0x10ACard responds 0x120DAQ sends 0x10ACard responds 0x12134901A in slot 3 of 34970A:I've added some comments as to what I think is happening.Code:At startup the uC RST-pin and the SRQ-pin is held high for aproximately 50ms.Then, after about 1400ms the following happens:DAQ Sends 0x119 (polls slot 1)DAQ sends 0x11A (polls slot 2)DAQ sends 0x11B (polls slot 3)Card responds 0x101 (type of card perhaps, 101=34901?)DAQ sends 0x123 (attention slot 3?)SRQ-signal goes high for 200ns, low for 16us and then high (where it stays)Card responds 0x121 (ACK?)200ms of silenceDAQ sends 0x16B, 0x030, 0x000 (0x16B has something to with the slot, the rest no idea)Card responds 0x121 (ACK?)5ms of silenceDAQ sends 0x16B, 0x030, 0x000Card responds 0x121 (ACK?)8ms of silenceDAQ sends 0x1BB, 0x000, 0x000, 0x000, 0x010170ms of silenceDAQ sends 0x10BCard responds 0x121The card knows which slot it's in via the backplace connector pins A6, A7 A8.EDIT: Perhaps I should add that I am probing at the plugin, not at the backplane or logic board - I should probably change that so that one can probe the system when multiple cards are fitted.

author: H.O
author_rank: Frequent Contributor
timestamp: May 14, 2022, 03:04:18 pm
content: Service guide does say 187500 9N1 so that's verified.It also says that the 9 bits consists of;a start bit, 8 data bits, an attention bit and a stop bit. The attention bit is 1 if the 8 databits are an address/command, or 0 if the 8 data bits modify or provide data for the previously sent command.I moved the probing from the module itself to the backplane connector. Now the SRQ doesn't do that short pulse that was seen before.When a slot is polled by the 0x119, 0x11A, 0x11B commands the card in the respective slot responds with it's ID where 0x101-0x108 is 34901-34908 respectively. I've verified this with 34901, 2, 3, 5 and 7.

author: voltsandjolts
author_rank: Unknown
timestamp: May 14, 2022, 03:12:32 pm
content: Wow, thanks H.O!...you work much faster than meThis is a great start.QuoteWell spotted, I got the baud setting from the manual but missed the explanation of the 9th bit.

author: H.O
author_rank: Frequent Contributor
timestamp: May 15, 2022, 01:12:00 pm
content: No problem, glad I can help.Not sure how to figure out what the rest of the bootup / configuration stuff actually does. Any ideas?Reading the relay count from the module was fairly easy to figure out.With 34901A in slot 1, pressing VIEW->RELAY CYCLES:(Display shows 7,141,391)Code:DAQ sends 0x169, 0x02C, 0x040Card responds 0x00FDAQ sends 0x149Card responds 0x0F8DAQ sends 0x149Card responds 0x06CDAQ sends 0x149Card responds 0x100Rotating the knob to select the next channel:(Display shows 673,436)Code:DAQ sends 0x169, 0x02C, 0x041 (Slot 1, Return relay count, Channel 2)Card responds 0x09C (Least significant byte)DAQ sends 0x149 (Slot 1, next byte please (0x14A for slot 2, 0x14B for slot 3))Card responds 0x046DAQ sends 0x149 (Slot 1, next byte please)Card responds 0x00ADAQ sends 0x149 (Slot 1, next byte please)Card resonds 0x100 (That's all I got)So, 0x169 targets card in slot 1 (will be 0x16A, 0x16B for the other two slots), 0x02C is the command to read relay cycles and 0x041 is the channel number.The card then returns one byte and the DAQ asks for the next byte by sending 0x149, 0x14A or 0x14B (depending on which slot it's targeting) until the card returns 0x100.The value is returnedmostleast significant byte first. For my channel 2: 0x0A469C = 673,436 which matches what's displayed on the DAQ itself.

author: voltsandjolts
author_rank: Unknown
timestamp: May 15, 2022, 02:31:29 pm
content: Looking at the block diagram for the 34901A we can guess at what some of the commands will be used for, e.g.~ open / close channel relays (as you have researched)~ open / close channel relays in 4 wire mode (maybe same commands as above?)~ Bank switches open/close for 4W mode~ open / close backplane switches for measure / 4w-sense / measureI~ read cold junction temperature (there are two DS75 chips on board so probably separate command to read each of them)~ read relay activation counters (as you have researched)There may also be commands to read 8051 firmware version and card hardware version.Things we don't understand can just be copied monkey-see-monkey-do for now.Note that I have not implemented the current measurement or the cold junction temperature measurement hardware. But still need dummy response to those commands of course.

author: strawberry
author_rank: Super Contributor
timestamp: May 16, 2022, 06:13:51 am
content: 0x16x execute - 0x02C function - 0x040 value - 0x121 executed / 0x100 end of data / 0x120 not ready/done / ..0x11x search0x1Bx write > flash memory ?0x12x activate - SRQ high - 0x121 executed0x14x received (card) data0x10x is data transmitted

author: voltsandjolts
author_rank: Unknown
timestamp: May 29, 2022, 04:02:42 pm
content: Making some progress on a rainy afternoon.The DMM sets the 9th bit when the character contains the card address. This reduces interrupt load on the card mcu, since the uart has an option to only interrupt if the9th bitis set. Once the card is addressed, it listens to all subsequent characters until that command is complete, processes it and then goes back into unaddressed mode again. The low 3 bits are used for card address, I guess they were allowing for an 8 slot dmm that never happened. Thus the command codes are actually 5 bits:Code:// Commands are shifted down 3 bits to remove the address bits and thus// allow the compiler to make a jump table with 32 entries for command decoding.#define CMD_IDENTIFY (0x18 >> 3) // response is 0x101-0x108 for 34901A-34908A cards respectively#define CMD_SRQ_TEST (0x20 >> 3) // card holds SRQ low for 16us then responds with 0x121#define CMD_UNKNOWN (0xB8 >> 3) // maybe for writing to eeprom...dunno#define CMD_QUERY_BUSY (0x08 >> 3)#define CMD_QUERY_DATA (0x48 >> 3) // read some data, byte at a time#define CMD_EXECUTE (0x68 >> 3) // begin read of relay cycle counts and other unknown stuff#define CMD_CHAN_CLOSE (0xE8 >> 3)#define CMD_CHAN_OPEN (0xE0 >> 3)#define CMD_CHAN_SCAN1 (0xD8 >> 3) // TODO don't understand this yet, scan channel list maybe?#define CMD_CHAN_SCAN2 (0x08 >> 3) // TODO don't understand this yetWhen responding to the DMM, the scan card sets the 9th bit to mean 'here is a data byte, and it's the last data byte I have for you right now'.I've implemented all the commands except the last two scan commands. Not tested yet.

author: bsdphk
author_rank: Regular Contributor
timestamp: May 29, 2022, 06:27:57 pm
content: Quote from: voltsandjolts on May 29, 2022, 04:02:42 pmThis is the good old "multidrop" bus from the MCS-51, aka intel 8051 microcontroller.And the 8-slot device exists, I've seen it on ebay, can't remember then umber.

author: razvan784
author_rank: Regular Contributor
timestamp: May 29, 2022, 07:27:26 pm
content: Quote from: bsdphk on May 29, 2022, 06:27:57 pmThere is an 8-slot 34980A, but it is of a newer design, having an Ethernet interface and wider modules.Some time ago I also attempted to design a sort of test board for reverse engineering the protocol and to act as a base for custom modules. Unfortunately I did not find enough time/motivation to actually build it yet, but attached are the schematic and PCB in KiCad 6 format - maybe someone will find them useful. It is centered around an 87C52 MCU, just like the original modules. Theoretically it should work with a MCU pulled from a working module (some versions have them socketed) - I thought that would help the debugging / reversing effort. Also a pin header is provided to monitor and override serial communication.

author: strawberry
author_rank: Super Contributor
timestamp: May 31, 2022, 04:52:39 am
content: AT89S52 seems compatible replacement

author: H.O
author_rank: Frequent Contributor
timestamp: June 01, 2022, 06:53:39 pm
content: I'm getting lost in my own notes...Sometimes, when being given a 0x109 command (for example during initialization or when manually opening/closing channels) the card responds with either 0x120 or 0x121. But other times (for example during a scan), it responds with 0x100 / 0x101 instead.Anyone been able to figure out the difference?(0xc8 >> 3) is likely the command to return reference junction temperature. I'm trying to figure out the data format but no luck so far.

author: voltsandjolts
author_rank: Unknown
timestamp: June 01, 2022, 07:18:09 pm
content: Quote from: H.O on June 01, 2022, 06:53:39 pmYeh, that has been irking me a bit. My latest guess is that0x121 ready (i.e. not busy)0x120 busy opening relays0x101 busy closing relays0x100 ...hmm hadn't noticed that oneQuoteYes, that starts off the read, getting a one byte response which is the LSB.The 3 remaining bytes are then read with the (0x48 >> 3) "read next byte in the transmit buffer" command. MSB last.Low 16 bits for ch1-10 CJ, high 16 bits for ch11-20 CJ.Exactly the same 4 byte transfer mechanism is used for the relay cycle counts.Looking at details of relay stuff now...At startup with genuine 34901A, the dmm sends (to card in slot 3) 1BB 000 000 000 010Been trying to figure that out, thought it might have been fram or CJ related but no.It ties in with relay driver activity (U102 pin1 toggling), so must be reseting relays....but takes 1.7sec to completePulseView capture attached for anyone interested.Progress so far with my card:It gets recognised and I can read dummy values for CJ temperatures and the relay cycle counts.

author: free_electron
author_rank: Super Contributor
timestamp: June 01, 2022, 07:51:02 pm
content: since its a 85c52 ... anyone tried dumping it ? The guy from The Signalpath did it with the VFD display processor.

author: voltsandjolts
author_rank: Unknown
timestamp: June 01, 2022, 08:04:19 pm
content: I've never tried, but theChinese clone 34901Auses their own firmware, so I'd bet the original is locked and unreadable.Anyway, I don't want to fraudulently use their copyrighted firmware. Honest open firmware is better, even if it has some foibles.

author: free_electron
author_rank: Super Contributor
timestamp: June 01, 2022, 11:23:47 pm
content: Quote from: voltsandjolts on June 01, 2022, 08:04:19 pmyou don't have to use it. simply decompile it. it's 4kilobyte...

author: strawberry
author_rank: Super Contributor
timestamp: June 02, 2022, 06:16:08 am
content: when in scan mode card sends channel status open/close ?I guess Chinese dont have thing like copyrightAgilent/Keysight... maybe still hold copyright back to 70's. Service manuals containing schematics are edited out on their website.

author: Kleinstein
author_rank: Super Contributor
timestamp: June 02, 2022, 06:33:32 am
content: The copyright for the old HP code still holds, however this only covers the direct copy of the code, not the functionality.As from international treaties the copyrights also applies in China - they just don't enforce it as strict.AFAIK it's for a minimum of 75 years. So not much computer code were the copyright has expired yet.As the function is relatively simple, there is no big issue in reprogramming it. This gives the freedom in using a difference µC type or just different pins and for te DIY version maybe alternative functions.

author: voltsandjolts
author_rank: Unknown
timestamp: June 02, 2022, 08:29:54 am
content: Quote from: free_electron on June 01, 2022, 11:23:47 pmSure, but then you are 'tainted' having seen the proprietary code, and you can no longer be part of any 'cleanroom' open source firmware effort.Whereas, observing the functionality of the device is legal.

author: strawberry
author_rank: Super Contributor
timestamp: June 02, 2022, 03:16:21 pm
content: copyright is for exact binary copy? does it apply for communication protocol as well. considering limitations it is possible to come up with same code or even better

author: free_electron
author_rank: Super Contributor
timestamp: June 02, 2022, 04:31:42 pm
content: Quote from: voltsandjolts on June 02, 2022, 08:29:54 amyou've seen assembly for an 8051. study the protocol and then rewrite it in different language for a different micro.

author: voltsandjolts
author_rank: Unknown
timestamp: June 02, 2022, 04:54:14 pm
content: Erm, I'm pretty sure that still referred to as 'copying'.

author: free_electron
author_rank: Super Contributor
timestamp: June 03, 2022, 06:40:25 pm
content: Quote from: voltsandjolts on June 02, 2022, 04:54:14 pmyou are not copying code. you looked at the code to derive the protocol. that protocol is then translated into a new programthat's how they did the IBM PC Bios. one group disassembled it , created a document detailing the API , tossed that document over the wall to another group of people that re implemented the API group 2 had never seen disassembly, only protocol spec.

author: razvan784
author_rank: Regular Contributor
timestamp: June 03, 2022, 07:07:47 pm
content: Quote from: free_electron on June 03, 2022, 06:40:25 pmYeah, that's the whole point, two different teams. To eliminate any reasonable suspicion of copying, it cannot be done by the same person. The procedure goes by the name "clean room reverse engineering".

author: H.O
author_rank: Frequent Contributor
timestamp: June 03, 2022, 10:56:33 pm
content: RegardingCode:#define CMD_CHAN_SCAN1 (0xD8 >> 3) // TODO don't understand this yet, scan channel list maybe?When using the front panel you can close more than one channel at the same time (depending on type of card). However,my guessis that the above command means "Open all closed channels, then close channel nn (followed by channel number)).Code:#define CMD_CHAN_SCAN2 (0x08 >> 3) // TODO don't understand this yetDon't think I've seen this one yet...what did you do to make the DAQ send that one?Am I correct that the cold junction reference temperatur is returned in units of 0.00390625°C per LSB? The DS75s datasheet says 12bits resoultion but I'm guessing the card CPU is doing some oversampling and is providing a psuedo 16bit result

author: voltsandjolts
author_rank: Unknown
timestamp: June 04, 2022, 10:56:38 am
content: Quote from: H.O on June 03, 2022, 10:56:33 pmAgree. When scanning a list of channels like:print(inst.query('MEAS:VOLT:DC? 10,(@101:112)'))The 0xD8 command is used like 'close ch1' then 'close ch2'...etc without any 'open' command.So yes, it opens the closed channels, then closes requested channel(s).There is also 0x1E1 0FF which seems to mean 'open all relays', including measurement bus relays and channel relays.QuoteMy bad ignore that..its dupilcate...thats the 0x08 CMD_QUERY_BUSY command.QuoteThe DS75s are used in 12bit mode (config byte is written at startup).They are sampled continuously (600ms interval alternatively).I haven't looked at what the scaling is, yes, maybe some averaging done there.Edit:I had expected the scaling to match the DS75 datasheet, but it's not quite the same.Examples of hex values I returned from my card and the resulting temperature (as read by Python script):Code:0x0000 == -9.012 (expected 0.0 degC)0x0873 == 0.0030x1910 == 24.352 (expected 25.0625 degC)0x7D00 == 124.290 (expected 125.0 degC)It's like the dmm is applying some additional calibration but I haven't seen values read from the card that look like calibration data.

author: voltsandjolts
author_rank: Unknown
timestamp: June 04, 2022, 11:02:14 am
content: My interpretation of commands so far:Code:// Commands are shifted down 3 bits to remove the address bits and thus// allow the compiler to make a jump table with 32 entries for command decoding.#define CMD_IDENTIFY (0x18 >> 3) // response is 0x101-0x108 for 34901A-34908A cards respectively#define CMD_SRQ_CLEAR (0x20 >> 3) // card holds SRQ low after power on, this cmd de-asserts it then responds with 0x121#define CMD_POWEROFF (0x40 >> 3) // see this 200ms before power off, address bits all zero i.e. 0x140 (broadcast addr?), no response required#define CMD_UNKNOWN (0xB8 >> 3) // 0x1B0 000 000 000 010 seen at power on, excercising or opening relays#define CMD_UNKNOWN2 (0xC0 >> 3) // seen at power on, no response so doesn't need implemented or mimicked#define CMD_QUERY_BUSY (0x08 >> 3) // response is either 0x100,0x101,0x120 (all busy in some way) or 0x121 (idle)#define CMD_QUERY_DATA (0x48 >> 3) // read data from the transmit buffer, byte at a time, last byte available has 9th bit set#define CMD_REFJUNC (0xC8 >> 3) // get reference junction temperatures (read from DS75 i2c temperature sensors)#define CMD_EXECUTE (0x68 >> 3) // begin read of firmware version, relay cycle counts and other unknown stuff#define CMD_CHAN_CLOSE (0xD8 >> 3) // close measurement bus and channel relays#define CMD_CHAN_OPEN (0xE0 >> 3) // 1E1 0FF seems to be "open all relays" for channels and measurement bus

author: voltsandjolts
author_rank: Unknown
timestamp: June 04, 2022, 11:18:06 am
content: If you use python for instrument control, here is the scrappy script I am using for experiments:Code:import pyvisa as visaimport time,sys#py -m pip install -U pyvisa#py -m pip install -U pyvisa-py (for the pure python backend)#py -m pip install -U pyserial#https://pyvisa.readthedocs.io/en/latest/index.html#How do I know if PyVISA-py is properly installed? Get info about PyVISA, the installed backends and their options:# python -m visa info#On Windows, you may have to uninstall the USBTMC specific driver installed by Windows and re-install a generic driver.#https://pyvisa.readthedocs.io/en/latest/introduction/configuring.html#rm = visa.ResourceManager('@py') # Use pure python backend#rm = visa.ResourceManager('@ivi') # Use IVI-VISA backendrm = visa.ResourceManager() # default backend#print('Available devices: ', rm.list_resources()) # Will show async serial devices (comports) as e.g. ASRL16::INSTR for COM16print('\nOpening device:')inst = rm.open_resource('USB0::0x0957::0x2007::MY57007585::INSTR') #For the 34972A on USB#inst = rm.open_resource("ASRL3::INSTR", baud_rate = 115200) #For the 34970A on RS232 (need to edit port number appropriately 'ASRL?' and check instrument baud setting)#reading and writing values:#https://pyvisa.readthedocs.io/en/latest/introduction/rvalues.html#inst.write('*rst; *cls') #reset to power on state, clear status# After *rst we now have these settings:# 1PLC, 5½ digits resolution# scaling is OFF and scale values are cleared# sets the scan interval to immediate (0 seconds) and the scan count to 1 sweep.DEFAULT_TIMEOUT = 5000 # default timeout is 5 secondsinst.timeout = DEFAULT_TIMEOUT#print(inst.query('*IDN?'))#print('Slot 1 card type:')#print(inst.query(':SYST:CTYPE? 100'))#print('Slot 2 card type:')#print(inst.query(':SYST:CTYPE? 200'))#print('Slot 3 card type:')#print(inst.query(':SYST:CTYPE? 300'))#print('Internal relay cycle count:')#print(inst.query('DIAG:DMM:CYCLES?'))#print(inst.query('CAL:SEC:STAT?'))#inst.write('CAL:SEC:STAT OFF,HP034970') #unsecure the instrument#print(inst.query('CAL:SEC:STAT?'))#inst.write('DIAG:REL:CYCL:CLE (@118)') #clears the relay cycle count on channel 18 in card slot 100#inst.write('DIAG:REL:CYCL:CLE (@118)') #clears the relay cycle count on channel 18 in slot 100#inst.write('DIAGnostic:DMM:CYCLes:CLEar 1') #clear internal DMM relay cycle count K102#inst.write('DIAGnostic:DMM:CYCLes:CLEar 2') #clear internal DMM relay cycle count K103#inst.write('DIAGnostic:DMM:CYCLes:CLEar 3') #clear internal DMM relay cycle count K104#inst.write('CAL:SEC:STAT ON,HP034970') #secure the instrument#inst.write("DISP:TEXT 'HELLO'")#time.sleep(1)#inst.write('DISPLAY:TEXT:CLEAR')#time.sleep(1)#inst.write('DISPLAY OFF') # Avoid screen burn on the VFD display by switching it off#time.sleep(1)####################### 20 Channel Card ###################### Assume this card is in slot 1, channels addresses are in 0x100 range# MEASure is equivalent to CONFigure followed by a READ?# These are the basic commands required# MEASure:VOLTage:DC? [{<range>|AUTO|MIN|MAX|DEF}[,{<resolution>|MIN|MAX|DEF}],] (@<scan_list>)# MEASure:RESistance? [{<range>|AUTO|MIN|MAX|DEF}[,{<resolution>|MIN|MAX|DEF}],] (@<scan_list>)# MEASure:FRESistance? [{<range>|AUTO|MIN|MAX|DEF}[,{<resolution>|MIN|MAX|DEF}],] (@<scan_list>)# MEASure:FREQuency? [{<range>|AUTO|MIN|MAX|DEF}[,{<resolution>|MIN|MAX|DEF}],] (@<scan_list>)#print('Slot1 relay cycle count:')#print(inst.query('DIAG:RELAY:CYCLES? (@101:120)')) # The relay cycle count from the chinese clone cards is always zero!!#print(inst.query('MEAS:VOLT:DC? 10,(@112:115)')) #10VDC range, default resolution#print(inst.query('MEAS:FRES? (@104)')) # 4W channels are paired. Specify channel 1 to 10, which is paired with 11 to 20.print(inst.query('MEAS:CURR:DC? 1,(@121:122)')) #1A range, default resolution#time.sleep(1) #1sec delayexit()# temperature stuff#inst.query('SENS:TEMP:TRAN:TC:TYPE K,(@101)')#inst.query('SENS:TEMP:TRAN:TC:RJUN:TYPE FIXED,(@101)')#print(inst.query('SENS:TEMP:RJUN? (@102)')) #read the internal ref junction temp for bank1 ch01-10 (from DS75 U152)#print(inst.query('SENS:TEMP:RJUN? (@118)')) #read the internal ref junction temp for bank1 ch11-20 (from DS75 U151)print(inst.query('MEAS:CURR:DC? 1,MAX,(@121)')) #1A DC range, 6½ digits of resolutionprint('\n---Measuring Examples---')print('Measure one channel:')print(inst.query('MEAS:VOLT:DC? 100,MAX,(@101)')) #100VDC range, 6½ digits of resolutionprint('Measure one channel:')print(inst.query('MEAS:VOLT:DC? 10,(@112)')) #10VDC range, default resolutionexit()print('Measure several sequential channels:')voltages = inst.query('MEAS:VOLT:DC? (@101:104)') #Auto ranging, default resolutionprint(voltages)print('Measure random channels:')inst.timeout = 20000 # 15 sec timeout for this longer operationprint(inst.query('MEAS:VOLT:DC? (@101:110,115,120)'))inst.timeout = DEFAULT_TIMEOUTprint('Measure 2W resistance:')print(inst.query('MEAS:RES? (@118)'))print(inst.query('MEAS:RES? (@101)'))print(inst.query('MEAS:RES? (@102)'))print('Measure 4W resistance:')print(inst.query('MEAS:FRES? (@109)')) # 4W channels are paired. Specify channel 1 to 10, which is paired with 11 to 20.

author: H.O
author_rank: Frequent Contributor
timestamp: June 05, 2022, 05:20:46 pm
content: QuoteHmmm...my impression is that 0x101, like 0x121, means confirmed/done/ready/idle - not busy.The scaling for the reference juctions is weird. It's not the 12bit format shown in the datasheet because the card returned values where the low 4 bits are not all zeros. My initial value of 125/32000 does not quite match, neither does 125/32768. My (genuine) card returns 0x17E4 for a reported temperature of 23.0156°C but the above scale factors eqauls 23.89 or 23.33. Like you say, there does not seem to be any calibration data transfered from the card.

author: voltsandjolts
author_rank: Unknown
timestamp: June 05, 2022, 06:22:54 pm
content: The 34970A service guide has some theory of operation explanation for the 34901A. It says the FRAM "provides data storage of the calibration constants for the analog output channels" which means the CJ temperature measurement. There is a calibration procedure for those also.But if the cal is in the FRAM, and I don't see it transferred to the DMM, it must be applied by the 8052 mcu. But then the scale for the CJ temperature values transferred to the meter doesn't make much sense either.I think I'll park this CJ stuff for now and just focus on relay channel stuff.

author: voltsandjolts
author_rank: Unknown
timestamp: June 05, 2022, 06:28:34 pm
content: Quote from: H.O on June 05, 2022, 05:20:46 pmAh, yeh, your right.After the open all command 1E1 0FF, status returns 0x100...0x120....0x121Close ch1 and status returns 0x100...0x101(where ... means lots of repeats)

author: voltsandjolts
author_rank: Unknown
timestamp: June 06, 2022, 12:44:46 pm
content: OK, I think I have enough understanding to carry on and make something kinda functional.Did I miss any commands?Code:// Commands are shifted down 3 bits to remove the address bits and thus// allow the compiler to make a jump table with 32 entries for command decoding.#define CMD_IDENTIFY (0x18 >> 3) // response is 0x101-0x108 for 34901A-34908A cards respectively#define CMD_SRQ_CLEAR (0x20 >> 3) // card holds SRQ low after power on, this cmd de-asserts it then responds with 0x121#define CMD_POWEROFF (0x40 >> 3) // seen 200ms before power off, address bits all zero i.e. 0x140 (broadcast addr?), no response required#define CMD_UNKNOWN (0xB8 >> 3) // 0x1B0 000 000 000 010 seen at power on, excercising (?) and opening relays, takes about 1.8sec#define CMD_POWERON (0xC0 >> 3) // seen at power on, no response required#define CMD_QUERY_BUSY (0x08 >> 3) // response for close cmd is 0x100...0x101 (idle), and for open cmd 0x100...0x120...0x121 (idle)#define CMD_QUERY_DATA (0x48 >> 3) // read data from the transmit buffer, byte at a time, last byte available has 9th bit set#define CMD_REFJUNC (0xC8 >> 3) // get reference junction temperatures (read from DS75 i2c temperature sensors)#define CMD_EXECUTE (0x68 >> 3) // begin read of firmware version, relay cycle counts and unknown (0x169, 0x030, 0x000/0x001)#define CMD_CHAN_OPEN (0xE0 >> 3) // open a channel, or 1E1 0FF to "open all relays" for channels and measurement bus#define CMD_CHAN_CLOSE1 (0xD8 >> 3) // scan mode, open all channels then close one channel relay and measure bus relays#define CMD_CHAN_CLOSE (0xE8 >> 3) // non-scan mode, allow multiple closed channels// The open and close commands are two characters long, the second specifies the channel:// 0x40-0x49 for channels 1 to 10// 0x80-0x89 for channels 11 to 20// 0x15-0x16 for channels 21 to 22 (current measurement only)// 0xC0-0xC9 for channels 1 to 10 in 4W resistance mode (paired with channels 11-20)// Additionally, the open command with "channel" 0xff means open all relays

author: strawberry
author_rank: Super Contributor
timestamp: June 06, 2022, 07:58:42 pm
content: 08A 40ch card

author: voltsandjolts
author_rank: Unknown
timestamp: June 06, 2022, 08:06:38 pm
content: I'm gonna focus on my 20 channel card, since I have a 34901A 20ch to study.I don't have a 34908A 40ch card, donations welcome!

author: strawberry
author_rank: Super Contributor
timestamp: June 07, 2022, 06:30:53 am
content: I have 3 empty slots

author: voltsandjolts
author_rank: Unknown
timestamp: June 08, 2022, 03:34:28 pm
content: OK, my SSR scan card seems to be working nicely, for 2w and 4w measurements.I'll add some comments to the code and tidy the schematic.Note that the 34901A card allows multiple channels to be closed at the same time, my card doesn't support that mode.In 2w mode, only one of the 20 channels can be closed at any one time.In 4w mode, the channel pairing works as it should, so one channel from each 'bank' is closed.Note also my card doesn't have hardware implemented for ch21/ch22 current measurement.Neither does it have the cold junction tempertaure sensors, but you can use an RTD instead (see 34970A manual), although that uses up one channel.Scaling for the CJ measurements sent to the dmm is not yet fully understood.I think this is the first 3rd party card for the 34970A/34972A.Since the dmm and cards are obsolete, this might breathe a little more life into them.The card is SSR so nice and quiet but with the protocol documented its easy enough to make your own custom card if you prefer armature, or want to add any of the missing features.Thank you for your help H.O.

author: voltsandjolts
author_rank: Unknown
timestamp: June 09, 2022, 09:52:31 am
content: Quote from: H.O on June 05, 2022, 05:20:46 pmI programmed my card to return that same value0x17E4and expected to see the same temperature reading as you. Nope!I got16.464°C from my 34972AI am confused about this, it's as if the calibration is somehow transferred to the dmm, but I still have not seen that on the uart bus.Edit:I am reading CJ temperature using these remote commands:inst.query('SENS:TEMP:RJUN? (@305)') #bank1 CJinst.query('SENS:TEMP:RJUN? (@315)') #bank2 CJHow are you reading the CJ?Maybe you're shorting the channel input and reading temperture from the channel?

author: strawberry
author_rank: Super Contributor
timestamp: June 09, 2022, 10:43:28 am
content: ''These adjustments are plug-in module specific and only affect thermocouplemeasurements. The calibration constants created by theseadjustments are stored in non-volatile memory on the plug-in module.''p112-113could see eeprom cal data while requesting tempDS75 max 2degC error

author: voltsandjolts
author_rank: Unknown
timestamp: June 09, 2022, 11:28:37 am
content: Quote from: strawberry on June 09, 2022, 10:43:28 amI thought that any cal data would get read at power-on but don't see it there.Maybe I'll try a long one minute capture just to be sure.I also looked for it upon the first CJ reading after power-on but again I didn't see anything.But yeh, it must be there somewhere, I just need some more time on it but can't right now.

author: H.O
author_rank: Frequent Contributor
timestamp: June 09, 2022, 05:59:54 pm
content: When I got the 0x17E4 value I was reading the CJ temp via SCPI (I don't think you can do it via the front panel?).I've done a 1 minute capture at power up and I don't see any calibration data. I've also configured a channel for T/C and as soon as you select Temperature the DAQ sends 0x1E1, 0x0FF (open all channels), then a 0x109/0x121 request/response, followed by the DAQ sending 0x169, 0x030, 0x001 which the card confirms with 0x121. After that nothing happens and I've let it sit idle for 5 minutes. A 34908A can't do TC but it's the exact same sequence when configuring a channel for temperature.If the calibration is applied by the card CPU then surely we'd get the same displayed value for the same raw value but we don't so the calibration "must" be applied by the main CPU but there does not seem to be any transfer of that data. With the 34907A there's a lot of traffic at the configuration stage and some of itseems to beoffset and gain calibration for the two DAC channels. Not so with the 34901A.For the 34908A the 40 channels are numbered straight from 0x001 to 0x028. Commands to close/open channels are the same as for the 34901A.EDIT: Still, that 0x169, 0x030, 0x001 is intereting, but the card just responds with 0x121. Perhaps the CJ compensation factors are lost and the FRAM has been re-initialised? But why would it try to read CJ calibration from a 34908A?

author: strawberry
author_rank: Super Contributor
timestamp: June 09, 2022, 06:24:19 pm
content: someone replaced with new EEPROM making card nonfunctional, if remember right

author: voltsandjolts
author_rank: Unknown
timestamp: June 09, 2022, 06:31:02 pm
content: Quote from: H.O on June 09, 2022, 05:59:54 pmI've just done the same. I agree, no cal data transfer there. Nor at time of reading first CJ temperature.QuoteYes, and everything would make sense, just a weird scaling of values for hex to °C.I'm going to check my result (0x17E4 == 16.464°C) again, in case I screwed up.Do you have a couple more hex values and associated °C CJ reading from your unit?Unfortunately I only have one 34972A here at the moment, no 34970A (there should be no difference 72/70A for this CJ stuff).

author: H.O
author_rank: Frequent Contributor
timestamp: June 10, 2022, 03:14:45 pm
content: 0x13FE = 20.031°C (low bank)0x1404 = 19.996°C (high bank)Then, when repeated about two minutes later I get the EXACT same values as above. Wait another minute or two:0x140E = 20.005°C0x140E = 20.005°CYes, it actually did return the same value for both banks. Then, another couple of minutes:0x1434 = 20.172°C0x143E = 20.226°CThen I warmed the card up with the heatgun:0x477E = 77.3750x3FA6 = 66.0040x3AFC = 62.7850x35EA = 55.4370x2A80 = 43.6290x296E = 41.805

author: voltsandjolts
author_rank: Unknown
timestamp: June 10, 2022, 03:15:34 pm
content: Edit:We were typing at the same time, I posted this some milliseconds after your post above/EditOK, I found the culprit of the confusion:When reading the CJ temperature, both bank1 and bank2 readings are sent by the card (16bits each).But the dmm uses some kind of weighted average of the two readings, weighted toward the bank CJ you requested.All our examples so far (of hex to °C) are null and void, because they were all influenced by what the other bank CJ reading was at the time.By setting both CJ readings to the same value, I can see the scaling used by the dmm:0x0000 = -7.109 °C0x17e4 = 23.180 °C0x7d00 = 124.289 °CThis scale is still odd, similar to the DS75 datasheet, but differentBut that's my understanding at the moment.You can't arrange your card to return exactly the same temperature hex for both CJ readings,.......but my 0x17e4 reading of 23.180 is very close to what you got 23.0156 (your card must have been temperature equalised).So, I think we are all good and we can assume the card applies the CJ calibration.

author: voltsandjolts
author_rank: Unknown
timestamp: June 10, 2022, 03:24:31 pm
content: Quote from: H.O on June 10, 2022, 03:14:45 pmHmm, when I program my card to return 0x140E for both CJ readings, I get 19.344°CClose, but not exact as I expectedEdit:I wonder if the dmm has an internal temperature sensor, and that is also included (to a small extent) into the weighted temperature average. Hmm....No. Can't be. For same hex values I get exact same TJ some 15mins later. If there were a third sensor in the mix, there would be some small change.It could be a time series average in the dmm, so 0x140E might be 19.344°C, and HO's card was cooling a little and showing time average of 20.005°C (delayed reading).....No. HO's reading show the card is warming slightly, over a few minutes.

author: tv84
author_rank: Super Contributor
timestamp: June 10, 2022, 03:28:37 pm
content: Why not read the temp for all the hex values and draw the line with the comparison? Or it's to cumbersome?With that you could probably discover what is the difference rule.

author: voltsandjolts
author_rank: Unknown
timestamp: June 10, 2022, 03:34:19 pm
content: Sure, but HO can only do a few points with his setup.I just wanted to see a perfect match to my setup with a few points.But maybe dmm averaging makes this impossible.

author: strawberry
author_rank: Super Contributor
timestamp: June 10, 2022, 06:36:17 pm
content: 70A cant find internal temp sensornothing interesting5118 20.031 5124 19.9965134 20.005 5134 20.0055172 20.172 5182 20.22610880 43.629 10606 41.80515100 62.785 13802 55.43718302 77.375 16294 66.004

author: voltsandjolts
author_rank: Unknown
timestamp: June 19, 2022, 03:06:27 pm
content: I have updated the first post in this topic to include the design files for this card.

author: voltsandjolts
author_rank: Unknown
timestamp: July 27, 2022, 11:37:50 am
content: Firmware updated to include relay cycle counters to demonstrate the DAQ commands.They are just in RAM, so start at 0 on every power-up.See first post to download.The cycle counters are accessed from python like this:Code:import pyvisa as visaimport time,sys#py -m pip install -U pyvisa#py -m pip install -U pyvisa-py (for the pure python backend)#py -m pip install -U pyserial#https://pyvisa.readthedocs.io/en/latest/index.html#How do I know if PyVISA-py is properly installed? Get info about PyVISA, the installed backends and their options:# python -m visa info#On Windows, you may have to uninstall the USBTMC specific driver installed by Windows and re-install a generic driver.#https://pyvisa.readthedocs.io/en/latest/introduction/configuring.html#rm = visa.ResourceManager('@py') # Use pure python backend#rm = visa.ResourceManager('@ivi') # Use IVI-VISA backendrm = visa.ResourceManager() # default backend#print('Available devices: ', rm.list_resources()) # Will show async serial devices (comports) as e.g. ASRL16::INSTR for COM16print('\nOpening device:')inst = rm.open_resource('USB0::0x0957::0x2007::MY57007585::INSTR') #For the 34972A on USB#inst = rm.open_resource("ASRL3::INSTR", baud_rate = 115200) #For the 34970A on RS232 (need to edit port number appropriately 'ASRL?' and check instrument baud setting)#reading and writing values:#https://pyvisa.readthedocs.io/en/latest/introduction/rvalues.html#inst.write('*rst; *cls') #reset to power on state, clear status# After *rst we now have these settings:# 1PLC, 5½ digits resolution# scaling is OFF and scale values are cleared# sets the scan interval to immediate (0 seconds) and the scan count to 1 sweep.DEFAULT_TIMEOUT = 5000 # default timeout is 5 secondsinst.timeout = DEFAULT_TIMEOUT#print(inst.query('*IDN?'))#print('Slot 1 card type:')#print(inst.query(':SYST:CTYPE? 100'))#print('Slot 2 card type:')#print(inst.query(':SYST:CTYPE? 200'))#print('Slot 3 card type:')#print(inst.query(':SYST:CTYPE? 300'))print('DAQ Internal relay cycle count:')print(inst.query('DIAG:DMM:CYCLES?'))print('Scan card relay cycle count:')print(inst.query('DIAG:RELAY:CYCLES? (@301:322)'))#Clear DAQ Internal or the scan card cycle counts like this:#print(inst.query('CAL:SEC:STAT?'))#inst.write('CAL:SEC:STAT OFF,HP034970') #unsecure the instrument '970A#inst.write('CAL:SEC:STAT OFF,AT034972') #unsecure the instrument '972A#print(inst.query('CAL:SEC:STAT?'))#inst.write('DIAG:REL:CYCL:CLE (@320)') #clears the relay cycle count on channel 20 in card slot 300#inst.write('DIAG:REL:CYCL:CLE (@118)') #clears the relay cycle count on channel 18 in card slot 100#inst.write('DIAGnostic:DMM:CYCLes:CLEar 1') #clear internal DMM relay cycle count K102#inst.write('DIAGnostic:DMM:CYCLes:CLEar 2') #clear internal DMM relay cycle count K103#inst.write('DIAGnostic:DMM:CYCLes:CLEar 3') #clear internal DMM relay cycle count K104#inst.write('CAL:SEC:STAT ON,HP034970') #secure the instrument '970A#inst.write('CAL:SEC:STAT ON,AT034972') #secure the instrument '972A

author: madao
author_rank: Frequent Contributor
timestamp: July 31, 2025, 04:06:12 pm
content: QuoteI have 3 card wird dead MCU (included killed DS75A )I have take working 34901A cardI have pulled working Intel 87C521 with Rev 1.1 marking (proably just a 87C52 OTP ) and read him with TL866CS.Reprogramming to ATmel 89S52 and put back to working 34901A card.-> yeah, card work with Atmel MCU ! (i have Version 1.1 and 2.0 reading via TL866CS, dump from broken MCU w rev 2.0 seems good, not checked )Rev 1.1 is for 34901A card with DS1620 temp sensor.BTW. read protected MCU give only 0xFF back...EDIT: 29.08.2025 Dump "Rev 2.0" from fried MCU works.

author: madao
author_rank: Frequent Contributor
timestamp: August 02, 2025, 03:48:19 am
content: i have here a rev 2.3 an some 34901A card (which it is soldered direct on PCBs)Rev 2.3 is newest MCU for 34901A & 34908A. Only my 34908A card has socket for Rev 2.3 MCUi am able to reading of content and flashing into 89S53 (loading 8052 content into TL866CS programmer without offset into 89S53, 89S53 is salvaged from old PCB)It works.