Electronics > Repair
Quick Repair: Standford Research PS350 5KV 5mA(Fixed but working on calibration)
<< < (4/11) > >>
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
Message Index
Next page
Previous page
There was an error while thanking
Thanking...

Go to full version
Powered by SMFPacks Advanced Attachments Uploader Mod