Read Signal from ADC on Raspberry Pi with FLTK

41 views
Skip to first unread message

LosCelos

unread,
Oct 20, 2020, 5:58:53 AM10/20/20
to fltk.general
Hi,

is there a way to read signals from an ADC on Raspberry Pi with FLTK ?
I already have installed FLTK on Raspberry Pi and make some Apps and it works.
But now i need to read data for example from a potentiometer which goes on a ADC MCP3008 and show the data on my FLTK on a scope like a oszilloskop.

I have the Oszilloskop-App to show the data.
And i can read the data from the ADC on my Raspberry Pi with a make-file (without FLTK).

The problem is that i have to read it with fltk to show it with the app.
Every data input should be shown instead, so there is no way to first put the data in a txt-file.

If you have any idea,
Thank you very much

Ian MacArthur

unread,
Oct 20, 2020, 6:24:46 AM10/20/20
to fltkg...@googlegroups.com
It’ll depend very much on what API your ADC presents (and how complicated you want to make things too, I suppose...)

Assuming your ADC presents some sort of C-callable API that acts as a FIFO or presents a buffer of data, say, then what I’d probably do myself is start the app in fltk, and create the UI, then spawn a worker thread to poll the ADC for input.

The worker then puts that data into a buffer, retaining on the last (however many you want to display) samples and the fltk main thread then reads that buffer periodically to refresh the display.

So, if you are comfortable with threads and such, that should be pretty straightforward. I you are not comfortable with threads... then this might be too complex a solution (sorry!)



Ian MacArthur

unread,
Oct 20, 2020, 6:35:34 AM10/20/20
to fltkg...@googlegroups.com
So it occurred to me that I must have code lying around that does basically this - but I went looking and couldn’t find anything directly suitable (work from home is strange...)

Anyway, attached a sample that *sort of* does what I described - this will not compile as-is, since it needs access to a separate audio input API I can not post here, but the basic idea is “the same”

This file creates a fltk window with a few widgets, then creates a worker thread called draw_wave() that loops around polling the audio port for input. That input is then copied into the buffer “sample” where it can be read by the fltk thread.

In the fltk thread, the timer callback method wave_CB() runs every 0.1 seconds to poll the sample data for changes. If there are changes, it refreshes the display accordingly.
So this is pretty incomplete, but there might be enough there to give you a few clues anyway... Note that there is a lot of spurious code to do with handling the buffers and so forth - your challenge is to figure out which bits matter and which bits are just my junk!

samples.cxx

LosCelos

unread,
Oct 20, 2020, 8:49:18 AM10/20/20
to fltkg...@googlegroups.com
Thank you very much guys,
i didnt work with threads yet, but i think i will learn it..

Thanks for the samples.cxx file, i will look it up, hopefully i find something which helps me.

Virenfrei. www.avast.com

--
You received this message because you are subscribed to a topic in the Google Groups "fltk.general" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/fltkgeneral/Ygjeyd9FNjI/unsubscribe.
To unsubscribe from this group and all its topics, send an email to fltkgeneral...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/fltkgeneral/3D4697E2-5413-4443-96C1-D0CC4E8D9259%40gmail.com.





--
You received this message because you are subscribed to a topic in the Google Groups "fltk.general" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/fltkgeneral/Ygjeyd9FNjI/unsubscribe.
To unsubscribe from this group and all its topics, send an email to fltkgeneral...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/fltkgeneral/3D4697E2-5413-4443-96C1-D0CC4E8D9259%40gmail.com.

Greg Ercolano

unread,
Oct 20, 2020, 10:36:49 AM10/20/20
to fltkg...@googlegroups.com
On 2020-10-20 03:24, Ian MacArthur wrote:
> So, if you are comfortable with threads and such, that should be pretty
> straightforward. I you are not comfortable with threads... then this might
> be too complex a solution (sorry!)

A possibly easier solution would just be to call fork() to start
a separate process, then the child can handle sending data to the
"Oszilloskop-App" as a realtime process, and the FLTK app can just
kill the process ID to stop it.

So if the FLTK app is simply a Start and Stop button for starting
the data hose to the Oszilloskop-App, then the start button starts
the child process to feed data to the scope, and stop kills the child
to stop it, e.g.

#include <unistd.h> // fork
#include <sys/types.h> // kill()
#include <signal.h> // kill()
..
pid_t G_child = 0;

// Your start button callback
void start_callback() {
if ( (G_child = fork()) == 0 ) {
// We are the child.. forever loop feed data to scope app
while ( 1 ) {
val = read_adc(); // whatever code reads the ADC
write_scope(val); // whatever code writes to the "Oszilloskop-App"
usleep(100); // yield some cpu to the rest of the machine for the scope app to run
}
}
}

// Your stop button callback
void stop_callback() {
if ( G_child == 0 ) return; // child already stopped? early exit
kill(G_child, 9); // stop child
if ( waitpid(G_child, NULL, 0); // wait for child to stop
, G_child = 0;
}

Depending on how "realtime" the data flow needs to be, you can use linux's
realtime API to adjust the child process to be unaffected by some system
hiccups, e.g. http://www.isy.liu.se/edu/kurs/TSEA81/lecture_linux_realtime.html
Message has been deleted

Greg Ercolano

unread,
Oct 21, 2020, 10:30:53 AM10/21/20
to fltk.general
>  it just works with a make-file.

    You'll need to merge the contents of your ADC app's Makefile with your FLTK app so that building
    the FLTK app can find the libraries your ADC function calls need, otherwise the linker can't know
    which library supplies the ADC functions.

    If you're not sure, (1) show us the contents of your ADC app's Makefile by attaching it here,
    (2) show us the commands/Makefile/whatever you're using to compile the FLTK app,
    and we can probably show you how to merge the two.


Message has been deleted

Albrecht Schlosser

unread,
Oct 21, 2020, 11:17:57 AM10/21/20
to fltkg...@googlegroups.com
On 10/21/20 4:48 PM LosCelos wrote:
> mistake from my side:
> i dont need the makefile. I can compile the shown adc program in
> terminal with: gcc testADC.c -o testADC -lwiringPi
>
> i compile the fltk App with: fltk-config --compile app.cxx
>
> the problem is that i cant put the needed  -lwiringPi in the compile
> line from the fltk

The "easiest" way to do this is to use `fltk-config --compile app.cxx`,
copy the command line you see and run the entire command on a new
command (copy and paste). Then "go back" one line in your shell
(typically by using the uparrow key) and edit the command line, i.e. put
'-lwiringPi' before or after '-lfltk' or at another appropriate place.

OTOH, I'd likely save the command file in a shell script and edit this
script for my build so I can easily repeat it. If you like you can also
use a combination of a simple Makefile that uses `fltk-config
--cxxflags' and `fltk-config --ld[static]flags' to get the proper FLTK
flags.

Given your command above, you could probably build your app using:

$ gcc `fltk-config --cxxflags` app.cxx -o app -lwiringPi `fltk-config
--ldstaticflags`

Copy and paste this line including the backticks (`) but w/o the '$'
sign and this should probably work.

Ian MacArthur

unread,
Oct 21, 2020, 11:21:57 AM10/21/20
to fltkg...@googlegroups.com
On 21 Oct 2020, at 15:48, LosCelos wrote:

mistake from my side:
i dont need the makefile. I can compile the shown adc program in terminal with: gcc testADC.c -o testADC -lwiringPi

i compile the fltk App with: fltk-config --compile app.cxx

the problem is that i cant put the needed  -lwiringPi in the compile line from the fltk


It probably is easier to do this with a Makefile - you will need to create one tailored to your project.

There are some notes you can follow:


and 


Might be good places to start.





is it possible to put the ADC code from above in my fltk App code, and it should some how know the reference, so that it dousnt throw: undefined reference to wiringPiSetup ?


Yes, but it will need to be done via callbacks and so forth. GUI programming is event driven, in general, so the simple linear progression of the sample code you show will not work.

Take a look at the fltk test samples, see how their code works.

In my original reply, I thought you were trying to build an oscilloscope, but if you simply want to display values from the ADC in “real time” then a simpler timer based approach will probably work.

Build a simple fltk app that updates it’s display in response to a timer (see Fl::add_timeout) and in the timer callback call the ADC API there to read the latest value and then display that on your display widget.

Set the timer to repeat at every 0.1 seconds and that will work fine. 

I’m not sure about the ADC that you are using but I’d assume you can probably poll it at 1kHz or so over the i2c bus. You can’t possibly display that many values though (your monitor will only be running at 60Hz, typically) and anyway humans can only parse values at about 10Hz, so refreshing the display any faster than that is just wasting pixels...

There are samples in the test and examples folder that demonstrate how to use the timers and how to make the callbacks, so you can easily start from there.




or do i have to start the ADC programm from my App with treads as you say before? If so, how i make my App knowing the ADC program to start it?


No, you can call the ADC API from your fltk program, in the timer callback if the update rate is low enough.
If you want to capture “all” the samples, you probably do need a separate thread to do that so that the ADC poll is independent of, and does not block, the GUI thread.

But do the timer approach first and once you understand how that works, head on to more challenging techniques!






Albrecht Schlosser

unread,
Oct 21, 2020, 11:25:29 AM10/21/20
to fltkg...@googlegroups.com
On 10/21/20 5:17 PM Albrecht Schlosser wrote:
> On 10/21/20 4:48 PM LosCelos wrote:
>> mistake from my side:
>> i dont need the makefile. I can compile the shown adc program in
>> terminal with: gcc testADC.c -o testADC -lwiringPi
>
> Given your command above, you could probably build your app using:
>
> $ gcc `fltk-config --cxxflags` app.cxx -o app -lwiringPi `fltk-config
> --ldstaticflags`

Correction (copy and paste error on my side): you need 'g++' instead of
'gcc' to compile the FLTK app since it's C++ code.

Ian MacArthur

unread,
Oct 23, 2020, 1:34:53 PM10/23/20
to fltkg...@googlegroups.com
I meant to post a worked example of the polling approach. But then I forgot...

Here is it anyway - I have commented out the R.Pi specific parts, and stubbed the read of the ADC, but it shows the basics of the timer polling approach...

With the ADC stuff added back in (and my dummy counter removed) this ought to pretty much work on the R.Pi, though you will need to link against wiringPi of course, as well as the fltk lib.

Something like this might do the trick to compile it:

g++ `fltk-config --cxxflags` app.cxx -o app -lwiringPi `fltk-config --ldstaticflags`

// Start of file

#include <FL/Fl.H>
#include <FL/Fl_Double_Window.H>
#include <FL/Fl_Value_Output.H>
#include <FL/Fl_Button.H>

// You would need these headers...
// #include <wiringPi.h>
// #include <mcp3004.h>

#define BASE 100
#define SPI_CHAN 0
#define chan0 0 /* Poti */
#define chan1 1 /* LDR */

static Fl_Double_Window *main_win = NULL;
static Fl_Value_Output *adc_out = NULL;

static int get_adc (void)
{
// This is where the ADC read would go...
//return analogRead (BASE);

// for now, here's a dummy test stub - reomve this!
static int dummy = 0;
++dummy;
if (dummy > 255) dummy = 0;
return dummy;
} // get_adc

// animate the meter for testing purposes
static void poll_adc (void *)
{
static int old_level = (-1);

int level = get_adc ();

if (level != old_level)
{
old_level = level;
adc_out->value (old_level);
adc_out->redraw();
}

Fl::repeat_timeout(0.1, poll_adc);
} // poll_adc

static void cb_Exit (void *)
{
main_win->hide();
} // cb_Exit

int main (int argc, char **argv)
{

// Setup wiringPi and mcp3004
// wiringPiSetup();
// mcp3004Setup(BASE, SPI_CHAN);

main_win = new Fl_Double_Window(247, 130);
main_win->begin();

adc_out = new Fl_Value_Output(100, 22, 66, 33, "ADC READ :");
adc_out->box(FL_THIN_DOWN_BOX);
adc_out->color(FL_WHITE);
adc_out->textfont(4);
adc_out->textsize(18);

Fl_Button* o = new Fl_Button(175, 80, 60, 25, "Exit");
o->box(FL_THIN_UP_BOX);
o->callback((Fl_Callback*)cb_Exit);

main_win->end();
main_win->show(argc, argv);

Fl::add_timeout(0.25, poll_adc);

return Fl::run();
} // main

// end of file





Reply all
Reply to author
Forward
Message has been deleted
0 new messages