Thread.Start: callback function with more than one argument?

I have a scenario where I want to sample 2 analog inputs, average them & store the averaged result to corresponding global variables (one for each input).

The code is identical for both inputs and currently I have 2 identical copies of the functions that are started in separate threads to continuously update the global vars. So far so good.

I want to rationalise this to a single function taking pointers to the analog input and global var.

The problem comes when attempting to start the thread(s) - it looks like the callback will only allow me to specify a single argument? is my reading of this correct? Is there a workaround or alternative method that will work?

Currently using mBedOS 5.15 on a EA NXP LPC4088QBS platform.

Code is below:

#include "mbed.h"

#define NSAMP       10
#define SAMP_INT    10

AnalogIn  incline_x(p15), incline_y(p16);

Thread roll_th, pitch_th;

volatile float g_roll_angle, g_pitch_angle;

Serial pc(USBTX, USBRX);

void angle_sample(float *g_angle, AnalogIn *a_inp) {
    uint8_t i = 0;
    uint16_t samples[NSAMP];
    uint32_t avg;

    while(true) {
        samples[i++] = a_inp->read_u16();                                    // read sample into array

        for(int j = 0; j < NSAMP; j++)                                          // loop over NSAMP samples & sum
            avg += samples[j];

        *g_angle = (((uint16_t)(avg/NSAMP) >> 8) * 0.44) - 67;             // store final value (converted to float) in global var
        
        avg = 0;                                                                // reset average

        i %= NSAMP;                                                             // mask array counter by modulus

        ThisThread::sleep_for(SAMP_INT);                                        // sample interval
    }
}

int main() {

    Thread thread;

    // start sampling threads
    roll_th.start(callback(angle_sample, &g_roll_angle, &incline_x);
    pitch_th.start(callback(angle_sample, &g_pitch_angle, &incline_y);

    // spin in a main loop. print ADC values
    while(1) {
        pc.printf("Roll: %+05.1f, Pitch: %05.1f\r\n", g_roll_angle, g_pitch_angle);
        ThisThread::sleep_for(1000);
    }
}

Hello Chris,

I think your reading is correct. Anyway, the angle_sample function doesn’t seem to be re-entrant. Hence, it should be protected by a mutex when shared by two threads:

...

Mutex           mutex;
...
void angle_sample(volatile float* g_angle, AnalogIn* a_inp)
{
    uint8_t     i = 0;
    uint16_t    samples[NSAMP];
    uint32_t    avg;

    while (true) {
        samples[i++] = a_inp->read_u16();   // read sample into array
        for (int j = 0; j < NSAMP; j++)     // loop over NSAMP samples & sum
            avg += samples[j];

        *g_angle = (((uint16_t) (avg / NSAMP) >> 8) * 0.44) - 67;   // store final value (converted to float) in global var
        avg = 0;                            // reset average
        i %= NSAMP;                         // mask array counter by modulus
    }
}

void roll_task()
{
    mutex.lock();
    angle_sample(&g_roll_angle, &incline_x);
    mutex.unlock();
    ThisThread::sleep_for(SAMP_INT);    // sample interval
}

void pitch_task()
{
    mutex.lock();
    angle_sample(&g_pitch_angle, &incline_y);
    mutex.unlock();
    ThisThread::sleep_for(SAMP_INT);    // sample interval
}

int main()
{
    Thread  thread;

    // start sampling threads

    roll_th.start(roll_task);
    pitch_th.start(pitch_task);
    ...
}

And in such case the two tasks won’t run effectively in “parallel” but rather in “sequence”.

Best regards, Zoltan

Thanks Zoltan!

Since the actual sampling rate is not critical (the input signal slew rate is of the order of 0.5V/s) I’ll give your suggestion a try.