Just tried the 34401-88813, and the double beeps still continue. But, I'm more confident that the problem isn't on the display board, because I disassembled the 34401-88813 display board firmware, looked at the other possible values that are sent (0xA5, 0x77, 0xBB, 0xDD), patched the firmware at 0x374 to try sending each of them, verified that they are sent with the logic analyzer, and have still observed no change. The two firmware are almost identical, except for a few small changes, so I went with the new one. Looks like I'll need to keep my eye out for a 1820-8907.
For reference, this is the function that is setting the SPI reply, which is called by the reset routine at startup:
code:0000036C ; =============== S U B R O U T I N E =======================================
code:0000036C
code:0000036C
code:0000036C code_36C: ; CODE XREF: RESET_0+A0p
code:0000036C ; code_800+15p ...
code:0000036C jb RAM_21.4, code_387 ; Jump if Bit is set
code:0000036F jb RAM_21.3, code_387 ; Jump if Bit is set
code:00000372 mov RAM_58, A ; Move (Op1 <- Op2)
code:00000374 mov RAM_5A, #0x77 ; 'w' ; FPDO
code:00000377 jnb RAM_22.4, code_381 ; Jump if Bit is clear
code:0000037A mov RAM_5A, #0xA5 ; ' ; FPDO
code:0000037D setb RAM_22.6 ; Set Direct Bit
code:0000037F clr RAM_22.4 ; Clear Operand (0)
code:00000381
code:00000381 code_381: ; CODE XREF: code_36C+Bj
code:00000381 setb RAM_21.3 ; Set Direct Bit
code:00000383 mov RAM_1A, #1 ; Move (Op1 <- Op2)
code:00000386 ret ; Return from subroutine
code:00000387 ; ---------------------------------------------------------------------------
code:00000387
code:00000387 code_387: ; CODE XREF: code_36Cj
code:00000387 ; code_36C+3j
code:00000387 mov RAM_55, A ; Move (Op1 <- Op2)
code:00000389 setb RAM_22.5 ; Set Direct Bit
code:0000038B
code:0000038B code_38B: ; CODE XREF: code_39D+32j
code:0000038B jbc RAM_22.4, code_390 ; Jump if Bit is set & clear Bit
code:0000038E
code:0000038E code_38E: ; CODE XREF: code_39D+20j
code:0000038E clr RAM_22.5 ; Clear Operand (0)
code:00000390
code:00000390 code_390: ; CODE XREF: code_36C:code_38Bj
code:00000390 setb RAM_21.2 ; Set Direct Bit
code:00000392 ret ; Return from subroutine
code:00000392 ; End of function code_36C
Note that bits 0 - 5 of RAM_21 and bits 1, 2, and 4 of RAM_22 are cleared earlier in RESET_0 before this function is called, so none of the branches at 0x36C and 0x36F are taken, whereas 0x377 is taken. But, RAM_21.3 is set at 0x381 before the function returns. The caller routine, RESET_0, is called by the reset vector, but also contains the main event loop for the microcontroller that never terminates. Right before it restarts the loop, it calls another function, which sends the SPI reply:
code:00000273 ; =============== S U B R O U T I N E =======================================
code:00000273
code:00000273
code:00000273 code_273: ; CODE XREF: RESET_0:code_23Ep
code:00000273 push PSW ; Program Status Word Register
code:00000275 mov PSW, #0x18 ; Program Status Word Register
code:00000278 jb RAM_21.5, code_2D7 ; Jump if Bit is set
code:0000027B jb RAM_21.4, code_2AC ; Jump if Bit is set
code:0000027E jb RAM_21.3, code_2AC ; Jump if Bit is set
code:00000281 jbc RAM_21.2, code_298 ; Jump if Bit is set & clear Bit
code:00000284 jb INT1, code_291 ; Port 3
code:00000287 setb T1 ; Port 3
code:00000289 mov P2, #0xFF ; Port 2
code:0000028C setb T0 ; Port 3
code:0000028E pop PSW ; Program Status Word Register
code:00000290 ret ; Return from subroutine
code:00000291 ; ---------------------------------------------------------------------------
code:00000291
code:00000291 code_291: ; CODE XREF: code_273+11j
code:00000291 jb RAM_21.3, code_2AC ; Jump if Bit is set
code:00000294 setb RAM_21.4 ; Set Direct Bit
code:00000296 sjmp code_2AC ; Short jump
code:00000298 ; ---------------------------------------------------------------------------
code:00000298
code:00000298 code_298: ; CODE XREF: code_273+Ej
code:00000298 setb RAM_21.3 ; Set Direct Bit
code:0000029A mov RAM_58, RAM_55 ; Move (Op1 <- Op2)
code:0000029D mov RAM_5A, #0x77 ; 'w' ; FPDO
code:000002A0 jnb RAM_22.5, code_2AA ; Jump if Bit is clear
code:000002A3 mov RAM_5A, #0xA5 ; ' ; FPDO
code:000002A6 setb RAM_22.6 ; Set Direct Bit
code:000002A8 clr RAM_22.5 ; Clear Operand (0)
code:000002AA
code:000002AA code_2AA: ; CODE XREF: code_273+2Dj
code:000002AA mov R2, #1 ; Move (Op1 <- Op2)
code:000002AC
code:000002AC code_2AC: ; CODE XREF: code_273+8j
code:000002AC ; code_273+Bj ...
code:000002AC setb T1 ; Port 3
code:000002AE mov P2, #0x7F ; '' ; Port 2
code:000002B1 clr T0 ; Port 3
code:000002B3 setb T0 ; Port 3
code:000002B5 mov P2, #0xFF ; Port 2
code:000002B8 clr T1 ; Port 3
code:000002BA clr EA ; Interrupt Enable Register
code:000002BC clr T0 ; Port 3
code:000002BE setb T0 ; Port 3
code:000002C0 setb T1 ; Port 3
code:000002C2 mov P2, RAM_5A ; FPDO
code:000002C5 clr T0 ; Port 3
code:000002C7 setb T0 ; Port 3
code:000002C9 clr T1 ; Port 3
code:000002CB setb TR0 ; Timer 0/1 Control Register
code:000002CD mov P2, #0xFF ; Port 2
code:000002D0 setb RAM_21.5 ; Set Direct Bit
code:000002D2 setb EA ; Interrupt Enable Register
code:000002D4 pop PSW ; Program Status Word Register
code:000002D6 ret ; Return from subroutine
code:000002D7 ; ---------------------------------------------------------------------------
code:000002D7
code:000002D7 code_2D7: ; CODE XREF: code_273+5j
code:000002D7 mov A, TL0 ; Timer 0, Low Byte
code:000002D9 anl A, #0xF8 ; Logical AND (op1 &= op2)
code:000002DB jz code_2EE ; Jump if Acc is zero
code:000002DD clr TR0 ; Timer 0/1 Control Register
code:000002DF mov TL0, #0 ; Timer 0, Low Byte
code:000002E2 mov R3, P2 ; Port 2
code:000002E4 setb T1 ; Port 3
code:000002E6 clr RAM_21.5 ; Clear Operand (0)
code:000002E8 mov DPTR, #0x2F1 ; Move (Op1 <- Op2)
code:000002EB mov A, R2 ; Move (Op1 <- Op2)
code:000002EC rl A ; Rotate Acc left
code:000002ED jmp @A+DPTR ; Jump indirect relative to Data Pointer
code:000002EE ; ---------------------------------------------------------------------------
code:000002EE
code:000002EE code_2EE: ; CODE XREF: code_273+68j
code:000002EE pop PSW ; Program Status Word Register
code:000002F0 ret ; Return from subroutine
code:000002F0 ; End of function code_273
On reset, the branches at 0x278 and 0x27B are not taken since those bits RAM_21.5 and RAM_21.4 are still (presumably) cleared, but since RAM_21.3 is now set, the branch at 0x27E is taken to 0x2AC, which skips over the block at 0x298 that would otherwise set the SPI reply to 0xA5/0x77, and writes out the contents of RAM_5A to port 2 at 0x2C2.