| Electronics > Repair |
| HP 3478A: How to read/write cal SRAM |
| << < (34/41) > >> |
| pqass:
So I ran an experiment... I enabled the cal screw on the faceplate and issued this command: echo -en "X\e\x0a\x41\r++read\r" >>/dev/ttyUSB0 My good cal was changed from (5th record beginning from hex address 35): --- Code: ---$ ./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 ... --- End code --- to failed record (crc!=ff): --- Code: ---$ ./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 ... --- End code --- The difference just happens to be the last (checksum) byte of the record. What I think happened is the "if (cfg.eoi)...else" branch (see code below) suppressed the 0A (hex) address byte I was targeting and instead used the next byte 41 (hex) as an address instead with the following byte \r or 0D (hex) as the byte to save at that address. CORRECTION: the \r would have been suppressed too. Hmmm... I don't know why exactly a D (hex) was saved but it definitely skipped the first 0A address byte because it changed the byte at 41 (hex)! CORRECTION to the CORRECTION: the second \r is from when the buffer is split; the 1st half being the X<addr><value> but the <value> is truncated. ie. the meter is using the end of line marker as the value to save. The SRAM is really only 4 bits wide so upon readback the meter just puts a 4 (hex) in the upper nibble, hence it returned "M" which is 4D (hex). From GPIBbus.cpp version 0.51.18: --- Code: ---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; } ... --- End code --- So how does this differ from AR488.ino 0.49.14: --- Code: ---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; } ... --- End code --- For 0.51.18, Wavey "fixed" the --- Code: ---if ((data[i] != CR) || (data[i] != LF) || ... --- End code --- code given that this will always return true. |
| WaveyDipole:
pqass, you kind of beat me to it, but yes, that is the explanation! --- Quote from: djrm on March 17, 2024, 08:31:14 pm ---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 --- End quote --- Thank you for test that and the result is as I suspected. It confirms what the problem is. In order to explain, it is necessary to consider the command sequence that is being sent to the meter in order to retrieve the cal data. To recap the command is: W<addr>, where <addr> is a single byte containing the memory address of the nibble to be read. Mark that. This is binary data, not text. The data is then followed by CRLF as a "line terminator" because ++eos is set to its default setting. Now here is the (now repeated) code from 0.49.14 which sends the data: --- Code: --- // 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; } --- End code --- I have removed the debug bit for clarity. We have a loop processing the buffer called data which contains the characters to be sent. In this case, the buffer contains 2 bytes: 0x57 and the <addr> byte, the terminators having been removed at the parsing stage. Note that if ++eoi is set to 1 (EOI asserting is on), then all characters in the buffer are written to GPIB. This is followed by terminators being added on according to to ++eos setting with EOI being signaled on the last character sent. However, if ++eoi is 0, then the 'else' clause comes into play. In this case, CR, LF and ESC characters are ignored. Why? Because if we are using CR, LF or CRLF as terminators without EOI, then we assume this to be a line of text which should not contain any additional terminator characters except those at its end. Nor should it contain an Escape (hex 0x27) character. However, if we take, for example address 10, we get the sequence: 0x57, 0x0A, then the 0x0A gets filtered but we still get the terminators added on according to the ++eos setting, so what actually gets sent is 0x57, 0x0D, 0x0A. The same would happen for address 13 and address 27. The problem with the above line is that each condition had been or'ed by mistake. This means that only one of the three conditions needed to be met in order for the statement to evaluate to true. This would result in any unexpected terminators or escape character being sent regardless. The error was corrected in later code by and'ing the conditions and changing the line to: --- Code: --- if ((data[i] != CR) && (data[i] != LF) && (data[i] != ESC)) state = writeByte(data[i], NO_EOI); --- End code --- Now, as intended, all three conditions must be met for the statement to evaluate to true and for the byte to be sent over GPIB. In short, the filtering now works as intended. The write command is slightly different in the restructured code but the effect is the same. Any unfiltered byte is written to the GPIB bus without using EOI and terminators are added at the end of the transmitted sequence. The inadvertent consequence of fixing this error has resulted in the behavioral change that has been observed here. In 0.49.14, addresses 0x10, 0x13 and 0x27 will have been sent regardless so reading the cal data worked correctly. In later fixed versions, those characters are no longer sent in text mode so they are omitted and we get an erroneous reading for those addresses. Address 43 (corresponding to the + character) is not affected. 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. |
| djrm:
--- Quote from: fenugrec on March 17, 2024, 09:08:25 pm ---Am I reading correctly that you guys are sending (as seen on GPIB) W \r <addr> \n ? --- End quote --- 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. David. |
| fenugrec:
--- Quote from: WaveyDipole on March 17, 2024, 10:07:18 pm --- 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. --- End quote --- As I recall (haven't worked on this in 3y), the prologix docs had a few grey areas wrt terminations. Here's how I interpreted and implemented in my firmware : 1- filter incoming bytes from host : - skip (don't change) escaped chars - convert unescaped \r to \n, - interpret \n as "end of chunk" and mark it. There may thus be two \n in a row after a conversion from \r to \n, but that is not a problem in later steps 2- parse chunks as either command or data, un-escaping as required. 3- if data, send on bus with EOS and EOI as required (There is no ambiguity on which chars must be sent on the bus, vs chunk termination from host) |
| pqass:
So what to do if EOI isn't on - that is, rely on \r or \n (or combo), whatever eos is set to, to signal an end of message. Stripping \r \n \e is currently a silent error since it can have side-effects to commands that accept binary data. How do you currently treat fatal errors like bus problems to control programs? Do you send error messages back? I think I recall seeing errors returned If verbose mode is on. Maybe you can return a message to say "\r \n \e were stripped, use eoi=1". At least if the user turns on verbose mode then he'll see it. |
| Navigation |
| Message Index |
| Next page |
| Previous page |