6 years, 7 months ago.

High accuracy measurement on NUCLEO L432KC

Hi there, I've created following code to measure the time between two pulses:

my code

#include "mbed.h"

Timer t;                        // timer to measure time between two sensor signals
Serial device(USBTX, USBRX); // for debug output on terminal
InterruptIn sensor(PA_9);       // for sensor signal

int32_t delta_us = 0;

void signalOccurred() {
    delta_us = t.read_us();     // global delta_us holds time difference between the last two signals now
    t.reset();                  // reset the timer
}

void sendMessage() {
    device.printf("Delta = %d\r\n", delta_us); //Debug out

    //send value via CAN here...
}

int main() {
    Timer sendViaCAN;
    device.baud(115200);
    device.printf("========== Device started up ==========\r\n");
    t.start();          //global
    sendViaCAN.start();
    sensor.rise(&signalOccurred);  // attach the address of the signalOccurred function to the rising edge

    // spin in a main loop and if signal occurs interrupt it!
    while(1) {
        if (sendViaCAN.read_ms() >= 20) {
            sendViaCAN.reset();
            sendMessage();
        }
    }
}

I've tested it with an Arduino board which has an hardware PWM. The problem with this code is, that it is giving me different results: the values changes several µs. This is not enough accuracy for me and I think the problem lies on the software side. - Is it possible to get a better accuracy with the NUCLEO L432KC?

1 Answer

6 years, 7 months ago.

Hello Peter,
I have tested the code below on NUCLEO-F103RB (using an LPC1768 mbed board as PWM signal generator) and it worked with 1us accuracy (in range from 10us to 4s).

#include "mbed.h"

//
enum State
{
    IDLE,
    READY,
    MEASURING,
    FINISHED,
    TIMEOUT
};

//
const float MEASUREMENT_TIMEOUT = 5.0f; // measurement timeout in seconds

//
Serial              pc(USBTX, USBRX);
InterruptIn         input(PA_9);
Timeout             timeout;
volatile State      state;
volatile uint32_t   now;
volatile uint32_t   begin;
volatile uint32_t   period;

/**
 * @brief   ISR handling 'measurement timeout'
 * @note    Called when input line is idle longer than expected.
 *          Signals 'end of measurement' by setting state to TIMEOUT.
 * @param   None
 * @retval  None
 */
void measurementTimeout(void) {
    input.disable_irq();
    timeout.detach();
    state = TIMEOUT;
}

/**
 * @brief   Measures pulse period (time elapsed between two rising edges)
 * @note    Waits until a rising edge is detected at input or timeout occured.
 * @param   None
 * @retval  None
 */
void measurePeriod(void) {
    bool    finished;

    state = READY;
    timeout.attach(callback(measurementTimeout), MEASUREMENT_TIMEOUT);
    input.enable_irq();

    do {
        finished = ((state == FINISHED) || (state == TIMEOUT));
    } while (!finished);
}

/**
 * @brief   ISR handling signal rise at input
 * @note    Called on signal rise at input
 * @param
 * @retval
 */
void onInputRise(void) {
    now = us_ticker_read();

    switch (state) {
        case READY:
            state = MEASURING;
            begin = now;
            break;

        case MEASURING:
            input.disable_irq();
            timeout.detach();
            state = FINISHED;
            period = now - begin;
            break;

        default:
            break;
    }
}

/**
 * @brief
 * @note
 * @param
 * @retval
 */
int main(void) {
    state = IDLE;
    input.mode(PullDown);
    input.disable_irq();
    input.rise(callback(onInputRise));

    while (1) {
        switch (state) {
            case IDLE:
                measurePeriod();
                break;

            case FINISHED:
                state = IDLE;
                pc.printf("Pulse period = %dus\r\n", period);
                wait(1);  // prevents PC's serial terminal from overloading when period is very short
                break;

            case TIMEOUT:
                state = IDLE;
                pc.printf("Measurement timeout. No signal detected at input.\r\n");
                break;

            default:
                break;
        }
    }
}

Zoltan