Ho-Ro / Hantek6022API

Hantek 6022BE Python API for Windows and Linux.
https://ho-ro.github.io/Hantek6022API/
Other
98 stars 15 forks source link

Missing pulses when calibration freq is set to 100kHz #12

Closed Ho-Ro closed 2 years ago

Ho-Ro commented 3 years ago

Mentioned there by @iss000: The problem is missing pulses when calibration freq is set to 100kHz (every lower freq is OK). image

The calibration pulse is created via timer2_isr() (source):

void timer2_isr( void ) __interrupt TF2_ISR {
    /* Toggle the probe calibration pin. */
    TOGGLE_CALIBRATION_PIN();
#ifdef LED_RED_TOGGLE
    if ( ledcounter && --ledcounter == 0 ) { // led timed out
        ledcounter = ledinit;                // reload
        LED_RED_TOGGLE();
    }
#endif
    TF2 = 0;
}

The timer is initialized in set_calibration_pulse() (source):

static BOOL set_calibration_pulse( BYTE freq ) {
    long frequency; // calibration frequency in Hz (32..100k)
...
    ledinit = frequency / 2;
    long rcap = -2e6L / frequency;
    RCAP2L = rcap & 0xff;
    RCAP2H = ( rcap & 0xff00 ) >> 8;
    return TRUE;
}

Debian buster version:

   1 ;--------------------------------------------------------
   2 ; File Created by SDCC : free open source ANSI-C Compiler
   3 ; Version 3.8.0 #10562 (Linux)
   4 ;--------------------------------------------------------
   5    .module dso6022be
   6    .optsdcc -mmcs51 --model-small
   7
...
1204 ;------------------------------------------------------------
1205 ;Allocation info for local variables in function 'timer2_isr'
1206 ;------------------------------------------------------------
1207 ;  scope6022.inc:76: void timer2_isr( void ) __interrupt TF2_ISR {
1208 ;  -----------------------------------------
1209 ;   function timer2_isr
1210 ;  -----------------------------------------
1211 _timer2_isr:
1212    push    acc
1213    push    psw
1214 ;  scope6022.inc:78: TOGGLE_CALIBRATION_PIN();
1215    cpl _PA7
1216 ;  scope6022.inc:80: if ( ledcounter && --ledcounter == 0 ) { // led timed out
1217    mov a,_ledcounter
1218    orl a,(_ledcounter + 1)
1219    jz  00108$
1220    dec _ledcounter
1221    mov a,#0xff
1222    cjne    a,_ledcounter,00121$
1223    dec (_ledcounter + 1)
1224 00121$:
1225    mov a,_ledcounter
1226    orl a,(_ledcounter + 1)
1227    jnz 00108$
1228 ;  scope6022.inc:81: ledcounter = ledinit;                // reload
1229    mov _ledcounter,_ledinit
1230    mov (_ledcounter + 1),(_ledinit + 1)
1231 ;  scope6022.inc:82: LED_RED_TOGGLE();
1232    cpl _PC0
1233 ;  assignBit
1234    setb    _PC1
1235 00108$:
1236 ;  scope6022.inc:85: TF2 = 0;
1237 ;  assignBit
1238    clr _TF2
1239 ;  scope6022.inc:86: }
1240    pop psw
1241    pop acc
1242    reti
1243 ;  eliminated unneeded mov psw,# (no regs used in bank)
1244 ;  eliminated unneeded push/pop dpl
1245 ;  eliminated unneeded push/pop dph
1246 ;  eliminated unneeded push/pop b

Debian bullseye version

   1 ;--------------------------------------------------------
   2 ; File Created by SDCC : free open source ANSI-C Compiler
   3 ; Version 4.0.0 #11528 (Linux)
   4 ;--------------------------------------------------------
   5    .module dso6022be
   6    .optsdcc -mmcs51 --model-small
   7
...
1198 ;------------------------------------------------------------
1199 ;Allocation info for local variables in function 'timer2_isr'
1200 ;------------------------------------------------------------
1201 ;  scope6022.inc:76: void timer2_isr( void ) __interrupt TF2_ISR {
1202 ;  -----------------------------------------
1203 ;   function timer2_isr
1204 ;  -----------------------------------------
1205 _timer2_isr:
1206    push    acc
1207    push    ar7
1208    push    ar6
1209    push    psw
1210    mov psw,#0x00
1211 ;  scope6022.inc:78: TOGGLE_CALIBRATION_PIN();
1212    cpl _PA7
1213 ;  scope6022.inc:80: if ( ledcounter && --ledcounter == 0 ) { // led timed out
1214    mov a,_ledcounter
1215    orl a,(_ledcounter + 1)
1216    jz  00108$
1217    mov a,_ledcounter
1218    add a,#0xff
1219    mov r6,a
1220    mov a,(_ledcounter + 1)
1221    addc    a,#0xff
1222    mov r7,a
1223    mov _ledcounter,r6
1224    mov (_ledcounter + 1),r7
1225    mov a,r6
1226    orl a,r7
1227    jnz 00108$
1228 ;  scope6022.inc:81: ledcounter = ledinit;                // reload
1229    mov _ledcounter,_ledinit
1230    mov (_ledcounter + 1),(_ledinit + 1)
1231 ;  scope6022.inc:82: LED_RED_TOGGLE();
1232    cpl _PC0
1233 ;  assignBit
1234    setb    _PC1
1235 00108$:
1236 ;  scope6022.inc:85: TF2 = 0;
1237 ;  assignBit
1238    clr _TF2
1239 ;  scope6022.inc:86: }
1240    pop psw
1241    pop ar6
1242    pop ar7
1243    pop acc
1244    reti
1245 ;  eliminated unneeded push/pop dpl
1246 ;  eliminated unneeded push/pop dph
1247 ;  eliminated unneeded push/pop b

As an intermediate containment action I reverted to the buster version of SDCC and set it on hold, see 81f6913:

the bullseye package (ver. 4.0.0) produces slower firmware code that leads to jitter of the 100 kHz calibration signal. workaround: install buster packages from sdcc_debian_old/sdcc_3.8.0.tgz with: "sudo apt install sdcc_3.8.0.deb" and set them to hold: "apt-mark hold sdcc; apt-mark hold sdcc-libraries"

Ho-Ro commented 2 years ago

Solution:

void timer2_isr( void ) __interrupt TF2_ISR {
    /* Toggle the probe calibration pin. */
    TOGGLE_CALIBRATION_PIN();
#ifdef LED_RED_TOGGLE
    // Avoid nasty sdcc 4.0 REGRESSION:
    // Do not use "if ( ledcounter && --ledcounter == 0 )"
    // Write separate statements!
    // Otherwise the ISR uses registers for reload -> additional push/pop ...
    // ... more cycles, fails for 100 kHz
    if ( ledcounter ) {
        --ledcounter;
        if ( ledcounter == 0 ) {  // led timed out?
            ledcounter = ledinit; // reload
            LED_RED_TOGGLE();
        }
    }
#endif
    TF2 = 0;
}

EDIT: SDCC 4.0 translates this into a faster asm code without registers:

1198 ;------------------------------------------------------------
1199 ;Allocation info for local variables in function 'timer2_isr'
1200 ;------------------------------------------------------------
1201 ;  scope6022.inc:76: void timer2_isr( void ) __interrupt TF2_ISR {
1202 ;  -----------------------------------------
1203 ;   function timer2_isr
1204 ;  -----------------------------------------
1205 _timer2_isr:
1206    push    acc
1207    push    psw
1208 ;  scope6022.inc:78: TOGGLE_CALIBRATION_PIN();
1209    cpl     _PA7
1210 ;  scope6022.inc:85: if ( ledcounter ) {
1211    mov     a,_ledcounter
1212    orl     a,(_ledcounter + 1)
1213    jz      00110$
1214 ;  scope6022.inc:86: --ledcounter;
1215    dec     _ledcounter
1216    mov     a,#0xff
1217    cjne    a,_ledcounter,00122$
1218    dec     (_ledcounter + 1)
1219 00122$:
1220 ;  scope6022.inc:87: if ( ledcounter == 0 ) {  // led timed out?
1221    mov     a,_ledcounter
1222    orl     a,(_ledcounter + 1)
1223    jnz     00110$
1224 ;  scope6022.inc:88: ledcounter = ledinit; // reload
1225    mov     _ledcounter,_ledinit
1226    mov     (_ledcounter + 1),(_ledinit + 1)
1227 ;  scope6022.inc:89: LED_RED_TOGGLE();
1228    cpl     _PC0
1229 ;  assignBit
1230    setb    _PC1
1231 00110$:
1232 ;  scope6022.inc:93: TF2 = 0;
1233 ;  assignBit
1234    clr     _TF2
1235 ;  scope6022.inc:94: }
1236    pop     psw
1237    pop     acc
1238    reti
1239 ;  eliminated unneeded mov psw,# (no regs used in bank)
1240 ;  eliminated unneeded push/pop dpl
1241 ;  eliminated unneeded push/pop dph
1242 ;  eliminated unneeded push/pop b
iss000 commented 2 years ago

Well done, it's fixed now. Thanks for the great work! Screenshot_20211117_180407 .