PaulStoffregen / FreqMeasureMulti

Measures the elapsed time during each cycle of up to 8 input frequencies.
34 stars 9 forks source link

Function isr() in FreqMeasureMultiIMXRT.cpp does not read correct capture register. #12

Open joepasquariello opened 3 years ago

joepasquariello commented 3 years ago

Description

Capture values computed in isr() are inaccurate for T4.x due to a bug in FreqMeasureMultiIMXRT.cpp

Steps To Reproduce Problem

Build/Run example sketch Single_PWM_In_Serial_Output on T4.0, with no changes. You'll see output like this:

60.02(2:2490368:16.60 2:2490368:16.60 2:2490368:16.60 2:2490368:16.60 )
59.97(2:2490368:16.60 2:2490368:16.60 2:2555904:17.04 2:2490368:16.60 )
60.02(2:2490368:16.60 2:2490368:16.60 2:2490368:16.60 2:2490368:16.60 )
59.97(2:2490368:16.60 2:2555904:17.04 2:2490368:16.60 2:2490368:16.60 )

Note the slightly inaccurate frequency values. The actual PWM frequency is 60.00 Hz. The measurement error is due to a bug in isr(). When the capture interrupt occurs (as opposed to the overflow interrupts), isr() reads register VALx, but that is not the capture register. It should be reading CVALx. In the output above, raw count values 2490368 (0x260000) and 2555904 (0x270000) are exact multiples of 65536. This is happening because isr() is incrementing msw on each overflow, but never reading the capture register to get the lower 16 bits.

With isr() changed to read CVALx, where X=0-5, rather than VALx, the output looks as shown below, with 60.00 Hz. No other changes are necessary outside isr().

60.00(2:2499968:16.67 2:2499968:16.67 2:2499968:16.67 2:2499968:16.67 )
60.00(2:2499968:16.67 2:2499968:16.67 2:2499968:16.67 2:2499968:16.67 )
60.00(2:2499968:16.67 2:2499968:16.67 2:2499968:16.67 2:2499968:16.67 )
60.00(2:2499968:16.67 2:2499968:16.67 2:2499968:16.67 2:2499968:16.67 )

Likewise, if you run the 3-PWM example sketch with the current library, you'll see this

60.02, 100.03, 199.90
59.97, 100.04, 200.07
60.03, 99.95, 200.07
59.97, 100.04, 199.97
60.02, 99.95, 199.90
59.97, 100.04, 200.07

And after the fix you'll see this

60.00, 100.00, 200.00
60.00, 100.00, 200.00
60.00, 100.00, 200.00
60.00, 100.00, 200.00
60.00, 100.00, 200.00
60.00, 100.00, 200.00 

Hardware & Software

Board T4.0 No shields / modules used Arduino IDE version 1.8.13 Teensyduino version Operating system & version Windows 7 Pro No other software or hardware

Arduino Sketch

You can see the issue via the existing example sketches. The ONLY change required in the library is in file FreqMeasureMultiIMXRT. .cpp, in function isr(), replace 6 instances of VALx with CVALx, where X=0-5.

Modified version of isr() shown below.

void FreqMeasureMulti::isr() { IMXRT_FLEXPWM_t *pflexpwm = freq_pwm_pin_info[_pin].pflexpwm; uint8_t sub_module = freq_pwm_pin_info[_pin].module & 3;

uint32_t capture;
bool inc = false;

// See if we have an overflow
if (pflexpwm->SM[sub_module].STS & FLEXPWM_SMSTS_RF) {
    pflexpwm->SM[sub_module].STS  = FLEXPWM_SMSTS_RF;   // clear the status
    capture_msw++;
    inc = true;
}
// This section handels inputs on Pin A
// We can probably combine and need to handle multiple pins on same one...
if (pflexpwm->SM[sub_module].STS & FLEXPWM_SMSTS_CFA0) {    // CAPTURE FLAG A0 (HINT)
    capture = pflexpwm->SM[sub_module].CVAL2;
    pflexpwm->SM[sub_module].STS = FLEXPWM_SMSTS_CFA0;      // clear status
    if (capture <= 0xE000 || !inc) {
        capture |= (capture_msw << 16);
    } else {
        capture |= ((capture_msw - 1) << 16);
    }
    processChannelISR(1, capture, 0);
}

if (pflexpwm->SM[sub_module].STS & FLEXPWM_SMSTS_CFA1) {    // CAPTURE FLAG A0 (HINT)
    capture = pflexpwm->SM[sub_module].CVAL3;
    pflexpwm->SM[sub_module].STS = FLEXPWM_SMSTS_CFA1;      // clear status
    if (capture <= 0xE000 || !inc) {
        capture |= (capture_msw << 16);
    } else {
        capture |= ((capture_msw - 1) << 16);
    }
    processChannelISR(1, capture, 1);
}
// This section handels inputs on Pin B
if (pflexpwm->SM[sub_module].STS & FLEXPWM_SMSTS_CFB0) {    // CAPTURE FLAG B0 (HINT)
    capture = pflexpwm->SM[sub_module].CVAL4;               // Guessing ? 
    pflexpwm->SM[sub_module].STS = FLEXPWM_SMSTS_CFB0;      // clear status
    if (capture <= 0xE000 || !inc) {
        capture |= (capture_msw << 16);
    } else {
        capture |= ((capture_msw - 1) << 16);
    }
    processChannelISR(2, capture, 0);
}
if (pflexpwm->SM[sub_module].STS & FLEXPWM_SMSTS_CFB1) {    // CAPTURE FLAG B0 (HINT)
    capture = pflexpwm->SM[sub_module].CVAL5;               // Guessing ? 
    pflexpwm->SM[sub_module].STS = FLEXPWM_SMSTS_CFB1;      // clear status
    if (capture <= 0xE000 || !inc) {
        capture |= (capture_msw << 16);
    } else {
        capture |= ((capture_msw - 1) << 16);
    }
    processChannelISR(2, capture, 1);
}

// This section handels inputs on Pin X
if (pflexpwm->SM[sub_module].STS & FLEXPWM_SMSTS_CFX0) {    // CAPTURE FLAG X0 (HINT)
    capture = pflexpwm->SM[sub_module].CVAL0;               // 
    pflexpwm->SM[sub_module].STS = FLEXPWM_SMSTS_CFX0;      // clear status
    if (capture <= 0xE000 || !inc) {
        capture |= (capture_msw << 16);
    } else {
        capture |= ((capture_msw - 1) << 16);
    }
    processChannelISR(0, capture, 0);
}

if (pflexpwm->SM[sub_module].STS & FLEXPWM_SMSTS_CFX1) {    // CAPTURE FLAG X0 (HINT)
    capture = pflexpwm->SM[sub_module].CVAL1;               // Guessing? 
    pflexpwm->SM[sub_module].STS = FLEXPWM_SMSTS_CFX1;      // clear status
    if (capture <= 0xE000 || !inc) {
        capture |= (capture_msw << 16);
    } else {
        capture |= ((capture_msw - 1) << 16);
    }
    processChannelISR(0, capture, 1);
}

}