Electronics > Repair
Quick Repair: Standford Research PS350 5KV 5mA(Fixed but working on calibration)
Dexter2:
I also got through a repair of one PS350 recently and done the GPIB upgrade trough a donors ROM. In the progress, I also loosen my calibration but luckily, it’s not so much off. But a possibility to calibrate it would be great.
Below the attached ROMs I have both V1.4 but quite different when I did the compare (GPIB vs Non-GPIB version), maybe they will help you to figure out where the calibration locations are more quicklly.
alm:
--- Quote from: smgvbest on July 30, 2017, 03:00:45 pm ---given that setting the DAC maybe possible what I imagine they do then is basically (and crudely)
[...]
--- End quote ---
I agree that it would probably be something like that (if they wanted to reduce calibration time, they would use some sort of binary search or interpolation for finding the offset).
Looks to me like WORD takes two comma-separated numbers that somehow may affect either vset, vlim, ilim or itrp. WORD? is also implemented and takes a single number. I believe the first parameter selects vset, vlim, ilim or itrp. Not sure what the point of this command is.
This looks to me like it might be subtracting calibration offsets. Depending on the value of port 0x28 bit 2 (J501 according to your earlier post, a calibration jumper? model indicator?), it uses 4026 or 4026+2A as base address. Then it does some math that as far as I can tell boils down to the parameter number (0..3) * 6. By my reading (which may very well be wrong), the first of the three words is an offset that is subtracted from the set voltage. Depending on the polarity of the result of this subtraction, it will either pick the second or third word and do something that looks like multiplication with it. If my analysis is correct, the calibration constants would live in 0x4026 up to something like 0x4082. Figuring out how the constants affect the DAC value should not be difficult by a more careful reading of the code.
--- Code: ---; a = { 0: vset, 1: vlim, 2: ilim, 3: itrp }
ROM:08FD loc_8FD: ; CODE XREF: check_limits+Ej
ROM:08FD push af
ROM:08FE ld a, (var_status2)
ROM:0901 bit 2, a
ROM:0903 ld hl, byte_4026
ROM:0906 jr z, loc_90B
ROM:0908 ld hl, byte_4026+2Ah
ROM:090B
ROM:090B loc_90B: ; CODE XREF: check_limits+2Bj
ROM:090B pop af ; a = param { 0..3 } << 1, e = a << 1, bc = var_vset
ROM:090C rlca
ROM:090D add a, e
ROM:090E ld e, a
ROM:090F add hl, de
ROM:0910 ld e, (hl)
ROM:0911 inc hl
ROM:0912 ld d, (hl)
ROM:0913 inc hl
ROM:0914 push hl
ROM:0915 ld h, b
ROM:0916 ld l, c
ROM:0917 or a
ROM:0918 sbc hl, de
ROM:091A pop de
ROM:091B jr c, loc_91F
ROM:091D inc de
ROM:091E inc de
ROM:091F
ROM:091F loc_91F: ; CODE XREF: check_limits+40j
ROM:091F ld a, 0
ROM:0921 call c, cpl_word ; hl = -hl
ROM:0921 ; a = 1
ROM:0924 ex de, hl
ROM:0925 ld c, (hl)
ROM:0926 inc hl
ROM:0927 ld b, (hl)
ROM:0928 ld (byte_40E6), a
ROM:092B pop af
ROM:092C push af
ROM:092D push bc
ROM:092E ld hl, 99Fh
ROM:0931 add a, l
ROM:0932 ld l, a
ROM:0933 jr nc, loc_936
ROM:0935 inc h
ROM:0936
ROM:0936 loc_936: ; CODE XREF: check_limits+58j
ROM:0936 ld a, (hl)
ROM:0937 cp 0
ROM:0939 jr z, loc_942
ROM:093B ld b, a
ROM:093C
ROM:093C loc_93C: ; CODE XREF: check_limits+65j
ROM:093C sla e
ROM:093E rl d
ROM:0940 djnz loc_93C
--- End code ---
This appears to be the code responsible for copying:
--- Code: ---ROM:0094 ld bc, 5Ch ; '\'
ROM:0097 ld hl, unk_1FA0
ROM:009A ld de, byte_4026
ROM:009D ldir
--- End code ---
$DAC seems to control the VSET DAC directly, ignoring any calibration constant or voltage setting (as expected). It does not appear to affect the other DACs like VLIM, ILIM and ITRP. So the calibration procedure would be something like:
--- Code: ---For DAC_VALUE in 0x0 0x7F 0x7FF 0x7FFF 0x807F 0x87FF 0xFFFF ; for a 16-bit DAC
$DAC DAC_VALUE
Measure voltage
Store DAC_VALUE, voltage
Then fit two linear functions of the form voltage -> DAC_VALUE for positive and negative voltages.
--- End code ---
Seems like it should be doable if you know the syntax of $DAC and the exact meaning of the constants. It will probably involve a lot of EPROM erase/flash cycles, however. Have you considered converting it to EEPROM? ;)
Let me know if all this makes sense and if it matches reality. I am not very familiar with Z80 assembly (had to keep the Z80 family CPU user manual open), and neither do I have access to one of these units, so I could easily be way off. There are definitely a few spots where I do not see how the code can do anything useful. I did go through a decent fraction of the code and have labeled a bunch of functions and variables. Especially around the GPIB commands and the DAC stuff.
smgvbest:
J501/J502/J503 monitor the polarity switch on the back of the supply. J501 would tell it is operating in POSITIVE, the pin is pulled high normally so a LOW would indicate Positive
J504 monitors the SET/MONITOR switch on the back of the supply. a HIGH should be SET, a LOW should be MONITOR
That word command may be how they read and/or set the each of those parms manually. perhaps part of their calibration process?
i'll try some commands to both $DAC and WORD and see what i get.
Sounds like WORD would be WORD? 1
FYI, the DAC used is a 12bit DAC
I have some 28C64's on the way ;)
appreciate all your assistance here. it's been very helpfull and seems to be right on.
if you are correct about the calibration values being in the 4026h range then this bit of code copies from EPROM to SRAM
--- Code: ---0079 0094 01 5c 00 ld bc,005ch ; transfer 5c bytes
0080 0097 21 a0 1f ld hl,1fa0h ; from eprom
0081 009a 11 26 40 ld de,4026h ; to sram @ 4026
0082 009d ed b0 ldir ; do the transfer
--- End code ---
this is the block of data being copied
--- Code: ---1FA0H 00001fa0h: AC 09 E4 55 0B 52 C4 09 54 52 54 52 BC 09 19 52 ; ¬.äU.RÄ.TRTR¼..R
00001fb0h: 53 4E BB 09 28 52 55 4E AC 09 E6 BF E2 C1 BD 09 ; SN».(RUN¬.æ¿âÁ½.
00001fc0h: E0 C1 E4 C3 00 00 93 43 93 43 A6 09 96 55 F6 51 ; àÁäÃ..“C“C¦.–UöQ
00001fd0h: C4 09 54 52 54 52 D1 09 31 51 30 4D D0 09 52 51 ; Ä.TRTRÑ.1Q0MÐ.RQ
00001fe0h: 22 4D A6 09 12 C0 E2 C1 D2 09 78 C2 84 C4 00 00 ; "M¦..ÀâÁÒ.x„Ä..
00001ff0h: 93 43 93 43 00 00 76 CA 00 00 76 CA ; “C“C..vÊ..vÊ
--- End code ---
Dexter2:
Just did the compare of two different V1.4 EPROMS.
The differences start from 0x01FA0 all the way to the end. So this all plays along with what has been discoverd so far by alm and smgvbest
alm:
Okay, then the two blocks are obviously for the negative and positive polarity. The first block would be used if J501 is low (positive polarity), and the second block for negative polarity. The use second or third word depends on the polarity of vset - word1. If this is negative, then the second word is used. Otherwise the second word is skipped and the third word is used. The result is fed in this function that I can not completely figure out:
--- Code: ---ROM:08A1 ; de = intermediate dac value (= word1 - vset)
ROM:08A1 ; hl = calib word 2 or 3
ROM:08A1
ROM:08A1 some_calc_hl_de: ; CODE XREF: check_limits+69p
ROM:08A1 ; sub_A39+3Bp ...
ROM:08A1 ld c, l
ROM:08A2 ld b, h
ROM:08A3 ld hl, 0
ROM:08A6 ld a, 10h
ROM:08A8
ROM:08A8 loc_8A8: ; CODE XREF: some_calc_hl_de+16j
ROM:08A8 sla l
ROM:08AA rl h
ROM:08AC rl e
ROM:08AE rl d
ROM:08B0 jr nc, loc_8B6
ROM:08B2 add hl, bc
ROM:08B3 jr nc, loc_8B6
ROM:08B5 inc de
ROM:08B6
ROM:08B6 loc_8B6: ; CODE XREF: some_calc_hl_de+Fj
ROM:08B6 ; some_calc_hl_de+12j
ROM:08B6 dec a
ROM:08B7 jr nz, loc_8A8
ROM:08B9 ret
ROM:08B9 ; End of function some_calc_hl_de
--- End code ---
Clearly the intermediate calibration value (word1 - vset) is added to an accumulator up to 0x10 times, depending on the value of word 2 / 3. Plus a bunch of bit shifting. Does anyone recognize this as a common mathematical function? Anyway, word 2 / 3 does seem some kind of multiplier/exponent. It presumably translates the signed 16-bit value to an unsigned 12-bit value.
This is the context of that function call. It comes immediately after the block I posted in my previous post:
--- Code: ---ROM:0942 loc_942: ; CODE XREF: check_limits+5Ej
ROM:0942 pop hl
ROM:0943 push de
ROM:0944 call some_calc_hl_de ; in:
ROM:0944 ; de = intermediate dac value
ROM:0944 ; hl = calib word 2 or 3
ROM:0944 ; out:
ROM:0944 ; hl = result
ROM:0944 ; de = ???
ROM:0947 bit 7, h
ROM:0949 jr z, loc_94C
ROM:094B inc de
ROM:094C
ROM:094C loc_94C: ; CODE XREF: check_limits+6Ej
ROM:094C pop hl
ROM:094D add hl, de
ROM:094E ld a, (byte_40E6)
ROM:0951 bit 0, a
ROM:0953 jr z, loc_957
ROM:0955 set 7, h
ROM:0957
ROM:0957 loc_957: ; CODE XREF: check_limits+78j
ROM:0957 pop af
ROM:0958 ret
--- End code ---
So after the operation the result hl is ignored, and the result de is added to (word1 - vset).
There may be some other data in there: by my math the four blocks of six bytes should only take 0x18 bytes, yet the second block starts at +0x2a (at 0x1fca). There does appear data between 0x1fb8 and 0x1fca. Is my understanding wrong? Or is this data really not used? If the second block is also 0x2a bytes long, it should stop at 0x1ff4, yet it copies until 0x1ffc.
This code appears to check an additional parameter block at 0x099F. This is a four byte block of zeroes in Sandra's ROM dump. This appears to indicate the number of iterations of the loop at 0x093c. So this could be an additional linearity correction or something (maybe used for different ranges, e.g. 5 kV vs 10 kV models). Though the different location in the firmware and the fact that it is not copied to RAM seems odd for calibration, and seems to argue for different models.
--- Code: ---ROM:092E ld hl, unk_99F
ROM:0931 add a, l
ROM:0932 ld l, a
ROM:0933 jr nc, loc_936
ROM:0935 inc h
ROM:0936
ROM:0936 loc_936: ; CODE XREF: check_limits+58j
ROM:0936 ld a, (hl)
ROM:0937 cp 0
ROM:0939 jr z, loc_942
ROM:093B ld b, a
ROM:093C
ROM:093C loc_93C: ; CODE XREF: check_limits+65j
ROM:093C sla e
ROM:093E rl d
ROM:0940 djnz loc_93C
ROM:0942
ROM:0942 loc_942:
--- End code ---
Actually, on second thought, it looks like WORD? can query words from the calibration RAM:
--- Code: ---ROM:1DE5 parse_word?: ; CODE XREF: ROM:1D7Aj
ROM:1DE5 ld hl, 2Dh ; '-'
ROM:1DE8 call get_gpib_num3
ROM:1DEB jp nz, end_of_string
ROM:1DEE push hl
ROM:1DEF call gpib_check_end_command
ROM:1DF2 pop hl
ROM:1DF3 jp nz, syntax_error
ROM:1DF6 ld de, byte_4026
ROM:1DF9 ex de, hl
ROM:1DFA add hl, de
ROM:1DFB add hl, de
ROM:1DFC ld e, (hl)
ROM:1DFD inc hl
ROM:1DFE ld d, (hl)
ROM:1DFF ex de, hl
ROM:1E00 call sub_1878
ROM:1E03 jp end_of_string
--- End code ---
The initial hl is the max input it accepts. So it expects a decimal integer up to 0x2d (45). And it adds this address twice to 0x4026. By my math that puts it two bytes short from the 0x5c bytes copied at 0x94. Either that or I made an off-by-one error. sub_1878 looks GPIB related, so may very well send a response back. I was also wrong about the WORD write. It appears to write the calibration RAM, and then changes the DAC setting to match the new calibration value. That was I was confused about it settings a value: it does call set_control value, but only to update the DAC with the new calibration constants. This is the complete code:
--- Code: ---ROM:1D77 parse_word:
ROM:1D77 call check_question_mark
ROM:1D7A jp z, parse_word?
ROM:1D7D ld hl, 2Dh ; '-'
ROM:1D80 call get_gpib_num3
ROM:1D83 jp nz, end_of_string
ROM:1D86 ld (var_temp_word_address), hl
ROM:1D89 call check_comma
ROM:1D8C jp nz, syntax_error
ROM:1D8F ld hl, 0FFFFh
ROM:1D92 call get_gpib_num3
ROM:1D95 jp nz, end_of_string
ROM:1D98 push hl
ROM:1D99 call gpib_check_end_command
ROM:1D9C pop hl
ROM:1D9D jp nz, syntax_error
ROM:1DA0 ld de, calibration_ram
ROM:1DA3 ld bc, (var_temp_word_address)
ROM:1DA7 ex de, hl
ROM:1DA8 add hl, bc
ROM:1DA9 add hl, bc
ROM:1DAA ld (hl), e
ROM:1DAB inc hl
ROM:1DAC ld (hl), d
ROM:1DAD ld a, c
ROM:1DAE cp 0Ch
ROM:1DB0 jr c, loc_1DBA
ROM:1DB2 sub 15h
ROM:1DB4 jr c, loc_1DE0
ROM:1DB6 cp 0Ch
ROM:1DB8 jr nc, loc_1DE0
ROM:1DBA
ROM:1DBA loc_1DBA: ; CODE XREF: ROM:1DB0j
ROM:1DBA cp 3
ROM:1DBC jr nc, loc_1DC5
ROM:1DBE ld a, 0
ROM:1DC0 call set_control_value ; a = { 0: vset, 1: vlim, 2: ilim, 3: itrp }
ROM:1DC3 jr loc_1DE0
ROM:1DC5 ; ---------------------------------------------------------------------------
ROM:1DC5
ROM:1DC5 loc_1DC5: ; CODE XREF: ROM:1DBCj
ROM:1DC5 cp 6
ROM:1DC7 jr nc, loc_1DD0
ROM:1DC9 ld a, 1
ROM:1DCB call set_control_value ; a = { 0: vset, 1: vlim, 2: ilim, 3: itrp }
ROM:1DCE jr loc_1DE0
ROM:1DD0 ; ---------------------------------------------------------------------------
ROM:1DD0
ROM:1DD0 loc_1DD0: ; CODE XREF: ROM:1DC7j
ROM:1DD0 cp 9
ROM:1DD2 jr nc, loc_1DDB
ROM:1DD4 ld a, 2
ROM:1DD6 call set_control_value ; a = { 0: vset, 1: vlim, 2: ilim, 3: itrp }
ROM:1DD9 jr loc_1DE0
ROM:1DDB ; ---------------------------------------------------------------------------
ROM:1DDB
ROM:1DDB loc_1DDB: ; CODE XREF: ROM:1DD2j
ROM:1DDB ld a, 3
ROM:1DDD call set_control_value ; a = { 0: vset, 1: vlim, 2: ilim, 3: itrp }
ROM:1DE0
ROM:1DE0 loc_1DE0: ; CODE XREF: ROM:1DB4j
ROM:1DE0 ; ROM:1DB8j ...
ROM:1DE0 ld c, 0
ROM:1DE2 jp end_of_string
--- End code ---
So if my theory is correct, WORD? 0 should return 0x09AC (probably as decimal and possibly in different endianess). WORD 0,256 should change the value at 0x4026 and WORD? 0 after that should return 256. Basically a peek and poke, but only for the calibration memory. If this works, then it would make reverse-engineering the calibration parameters a whole lot faster and save a lot of wear and tear on the EEPROM burner.
Navigation
[0] Message Index
[#] Next page
[*] Previous page
Go to full version