8 ADC input @20 KHz

Oh, I probably forgot the most important part. Never stop learning. For me I love learning, maybe even more than actually getting anything done heh.

No in my case 50 - 60 samples are not sufficient in my case.why? let me explain my objective in a brief:

" I want to sample power supplied, So my basic waveform is of 50 /60 Hz but supply is coming from inverter( DC to AC converter) and as its coming from converter it will have high frequency harmonics / noise; bcoz inverter switching freq can be from 4 KHz to 6 KHz ".
Hence as per Nyquist criteria, to reconstruct or analyze, I require samples at higher freq than the that.

Hope it clears the things :slight_smile:

Once again my sincerest gratitude for guidance.

Oh yes, I also LOVE learning… Thats why I have taken this project. Actually I am from electrical background, Power system to be precise, but thought of taking a walk on wild side :wink: though feeling the heat but, yeah…

I liked your casual approach, Thank you for the insight…!!

Modified sine or true sine ?

One thing that did cross my mind earlier. I seemingly forgot to post.

First, try running time ./test with sudo so…

$ sudo time ./test

If this works, then it’s a permission issue. I really do not think this is the problem, but it possibly could be.

Second, change:

void read_adc(int fd)
{
char adc[5] = {0};
int len = read(fd, adc, sizeof(adc - 1));
adc[len] =‘\0’;
printf("%s ", adc);
}

To
void read_adc(int fd)
{
char adc[5] = {0};
int len = read(fd, adc, sizeof(adc - 1));
if(len == -1){
printf(“error: %s\n”, strerror(errno));
exit(1);
}
else if(len == 0){
printf(“%s\n”, “buffer is empty”);
}
else{
adc[len] =‘\0’;
printf("%s ", adc);
}
}

What this does is give us more error control, and possibly a clue as to the problem with this executable on your system. If there is an error the program will exit, and give you the reason why. If the buffer in empty, this possibly means you’re running in continuous mode, and these pseudo files are empty( unused ). I’m thinking one of these two should be the output you’ll get. If not, then I’d have to do more reading to find out exactly why, but.

If you have a spare sdcard, and install the same image you have now on it. Well flash from the standalone command line image for 3.8.x. Then follow the guide I put up on updating device tree files, including upgrading the kernel to the one I’ve shown. That would be great. As it would allow you to keep your older image too just in case this does not work out for you. Or if you have a Linux system, you could use dd or tar to backup the rootfs, save it, and then wipe the sdcard you do have clean. And start fresh. It could be that libpruio is somehow involved in that code not working properly.

Hi, Its supposed to be true sine but due to switching harmonics & other non-linearity it will be MODIFIED SINE.

And OKK, I do have a spare SDcard, I will put an new image and do your steps and see if it works or not.

Though It will take some time for me, coz I have not done kernel patching & compilation.

Will get back to you as soon as I have a card ready & results.

And no, I dont think libpruio is a problem cause, I didnt liked it while compiling your code & to my (limited) knowledge, libpruio dose not make any permanent changes to the system.

Hi Rathin!

I didn’t read all the stuff in the posts of this thread. But most of it seams irrelevant. Forget it.

You’re using libpruio. That’s the only way to reach your target → That’s OK.

You cannot reach 20 kHz sampling rate due to two reasons:

  • you’re using default step configuration. This is 183 cycles open delay and avaraging 4. That means 183 + 1 + 4 x 14 cycles for each sample (@ 24 MHz) = 10 kHz per channel. Therefor maximum sampling rate for 8 channels is 1.25 kHz.
  • you’re using IO mode. The ARM CPU determines the sampling speed and your printf statement slows down the program execution, so you don’t get the previous mentioned 1.25 kHz.

In order to reach 20 kHz sampling rate you have to do

  1. configure customized steps for fast sampling (ie. no open delay and no avaraging)
  2. use either MM or RB mode to get accurate timing

Either have a look at the triggers example (to use MM mode) or check out the following code (comming from an example named rb_file for next libpruio versions)

`
/** \file rb_file.c
\brief Example: fetch ADC samples in a ring buffer and save to file.

This file contains an example on how to use the ring buffer mode of
libpruio. A fixed step mask of AIN-0, AIN-1 and AIN-2 get configured
for maximum speed, sampled in to the ring buffer and from there saved
as raw data to some files.

Licence: GPLv3

Copyright 2014-2015 by Thomas{ dOt ]Freiherr[ At ]gmx[ DoT }net

Thanks for C code translation: Nils Kohrs <nils[ dot ]kohrs{ AT }gmail[ dOt ]com>

Compile by: gcc -Wall -o rb_file rb_file.c -lpruio -lprussdrv

\since 0.2.0.2
*/

#include “unistd.h”
#include “time.h”
#include “stdio.h”
#include “…/c_include/pruio.h”

//! The main function.
int main(int argc, char **argv)
{
const uint32 tSamp = 123401; //!< The number of samples in the files (per step).
const uint32 tmr = 5000; //!< The sampling rate in ns (5000 → 200 kHz).
const uint32 NoStep = 3; //!< The number of active steps (must match setStep calls and mask).
const uint32 NoFile = 2; //!< The number of files to write.
const char *NamFil = “output.%u”; //!< The output file names.
struct timespec mSec;
mSec.tv_nsec=1000000;
pruIo *io = pruio_new(PRUIO_DEF_ACTIVE, 0x98, 0, 1); //! create new driver
if (io->Errr){
printf(“constructor failed (%s)\n”, io->Errr); return 1;}

do {
if (pruio_adc_setStep(io, 9, 0, 0, 0, 0)){ // step 9, AIN-0
printf(“step 9 configuration failed: (%s)\n”, io->Errr); break;}
if (pruio_adc_setStep(io,10, 1, 0, 0, 0)){ // step 10, AIN-1
printf(“step 10 configuration failed: (%s)\n”, io->Errr); break;}
if (pruio_adc_setStep(io,11, 2, 0, 0, 0)){ // step 11, AIN-2
printf(“step 11 configuration failed: (%s)\n”, io->Errr); break;}

uint32 mask = 7 << 9; //!< The active steps (9 to 11).
uint32 tInd = tSamp * NoStep; //!< The maximum total index.
uint32 half = ((io->ESize >> 2) / NoStep) * NoStep; //!< The maximum index of the half ring buffer.

if (half > tInd){ half = tInd;} // adapt size for small files
uint32 samp = (half << 1) / NoStep; //!< The number of samples (per step).

if (pruio_config(io, samp, mask, tmr, 0)){ // configure driver
printf(“config failed (%s)\n”, io->Errr); break;}

if (pruio_rb_start(io)){
printf(“rb_start failed (%s)\n”, io->Errr); break;}

uint16 *p0 = io->Adc->Value; //!< A pointer to the start of the ring buffer.
uint16 *p1 = p0 + half; //!< A pointer to the middle of the ring buffer.
uint32 n; //!< File counter.
char fName[20];
for(n = 0; n < NoFile; n++){
sprintf(fName, NamFil, n);
printf(“Creating file %s\n”, fName);
FILE *oFile = fopen(fName, “wb”);
uint32 i = 0; //!< Start index.
while(i < tInd){
i += half;
if(i > tInd){ // fetch the rest(no complete chunk)
uint32 rest = tInd + half - i;
uint32 iEnd = p1 >= p0 ? rest : rest + half;
while(io->DRam[0] < iEnd) nanosleep(&mSec, NULL);
printf(" writing samples %u-%u\n", tInd -rest, tInd-1);
fwrite(p0, sizeof(uint16), rest, oFile);
uint16 *swap = p0;
p0 = p1;
p1 = swap;
}
if(p1 > p0) while(io->DRam[0] < half) nanosleep(&mSec, NULL);
else while(io->DRam[0] > half) nanosleep(&mSec, NULL);
printf(" writing samples %u-%u\n", i-half, i-1);
fwrite(p0, sizeof(uint16), half, oFile);
uint16 *swap = p0;
p0 = p1;
p1 = swap;
}
fclose(oFile);
printf(“Finished file %s\n”, fName);
}
} while(0);
pruio_destroy(io);
return 0;
}

`
Desription

`
rb_file {#SubSecExaRbFile}

Dear Thomas,

First of all, Thanks a lot for coming by and answering, I respect your efforts in developing in libpruio!! I cant imaging how much work you must have put in…! :slight_smile:

Well, second things is you mean to say if I use 8 ADCs I cant achieve 1.25Khz+ sample rate, Than should I use external ADC? would it be easier?

and to be frank I have plenty of doubts in the pruio construct and pruio_config, I which are as follows:

  • You said I have 183 cycle open delay - but where is it? I have made everything 0 ( zero!!) you can have a look at option setting in line bellow!!

  • pruio_new(PRUIO_DEF_ACTIVE, 0, 0, 0)

  • And in my pruio_config, I have made averaging to 0 (you can see that as well). delay 0,

  • pruio_config(io, 1, PRUIO_DEF_STPMSK , 0, 4)

So, is my configuration is wrong or the approach?

few queries with respect to your new example

  • This is also for only 3 ADC channels, so if I extend it for 8, will this one also become slow?

  • I am going to “monitor” the inputs continuously, so I require continuous stream of input, will this approach work?

  • Its later part of my project but I saw u using system timer so asking that I also want to time stamp the data with system time, so can it be done here or should I do it later?

Sorry if my queries sound novice but I am new to this & I am felling overwhelmed by the whole thing…!! :slight_smile:

I have been reading the processor TRM and PRU reference manual and I petrified, its kind of ocean of information. ( it remind me of “The old man & the sea”!! )

Sincerely,

Rathin

PS:

There is only one ADC in the sitara processor.
There is a 8 to 1 mux to provide you with 8 inputs.
If you want really fast multi channel ADC conversions you may want 8
separate ADC Chips external
to the processor.

So, let me say what is not irrelevant. Standardization, documentation, and usability. It is my personal opinion that the documentation for libpruio could use A LOT of work. Which leads to the third thing I mentioned above. I also do not feel that the whole library is open enough. Last I looked, one had to download a pre-compiled binary in order to make it work. This is not open source, which is big on many peoples mind.

So, if I seem like I have not a clue as to how libpruio works. That would be correct. Because if the documentation is not good enough for me to read, and understand what is going on, I’m not going to bother with the whole situation.

Why ? Because there are other methods to do the same thing, that are open sourced, are documented very well, and are standardized. I would rather invest my time into understanding these things. Instead of attempting to reinvent the wheel - As it were.

Does this mean I think libpruio is garbage. No! This means I think there are several things concerning the library that can use some improvement. Which personally I do not care to invest my time into.
. . .

Dear Wulf man,
Thanks for the input. So do you recommend that external ADC and communicate through PRU with SPI, GPIO?

and do you have some good ADC IC in mind?

Dear Wulf man,

Hi Rathin!

Well, second things is you mean to say if I use 8 ADCs I cant achieve 1.25Khz+ sample rate, Than should I use external ADC? would it be easier?

The internal ADC can achieve up to 25 kHz sampling rate for 8 channels. Using an external ADC wouldn’t be easier, but you may have reasons for that (which you didn’t specify yet): ie. like more than 12 bit resolution, lower impedancy, …

and to be frank I have plenty of doubts in the pruio construct and pruio_config, I which are as follows:

  • You said I have 183 cycle open delay - but where is it? I have made everything 0 ( zero!!) you can have a look at option setting in line bellow!!

  • pruio_new(PRUIO_DEF_ACTIVE, 0, 0, 0)

I missed that line, sorry. (I’m not used to C syntax.) This is one way to override the default step configuration. So your code already solves point 1 in my above post.

  • And in my pruio_config, I have made averaging to 0 (you can see that as well). delay 0,

  • pruio_config(io, 1, PRUIO_DEF_STPMSK , 0, 4)

The zero in that line means Tmr = 0. Since you set Samp = 1, you’re operating in IO mode. In that case parameter Tmr has no function. Tmr is used in MM or RB mode. It specifies the sampling rate (for all channels).

So, is my configuration is wrong or the approach?

Your configuration is OK, but your main loop is too slow. The fprintf statement is too slow to get the desired sampling rate. libpruio serves the samples, but the ARM CPU doesn’t get them all (some get skipped).

Instead of using fprintf(), you could try to write binary numbers by function fwrite() and convert to ASCII numbers later.

few queries with respect to your new example

  • This is also for only 3 ADC channels, so if I extend it for 8, will this one also become slow?

As Wulf Man said:

There is only one ADC in the sitara processor.
There is a 8 to 1 mux to provide you with 8 inputs.

Each additional channels slows down the overall sampling rate, which is 200 kHz for one step, 100 kHz for two steps, …, 25 kHz for 8 steps

  • I am going to “monitor” the inputs continuously, so I require continuous stream of input, will this approach work?

It isn’t easy to monitor 8 channels @ 20 kHz by the ARM CPU. The CPU load generated by the OS like interrupts or multitasking may get too big.

I’d do the measurements by libpruio running on PRU-1 in RB mode and do the monitoring by customized real-time ASM code running on PRU-0.

  • Its later part of my project but I saw u using system timer so asking that I also want to time stamp the data with system time, so can it be done here or should I do it later?

Sorry, I’ve not enough infromation to give any statement here.

BR

Hey William, thanks for your statements. (In bad mood again?)

I also do not feel that the whole library is open enough. Last I looked, one had to download a pre-compiled binary in order to make it work. This is not open source, which is big on many peoples mind.

Where did you find that? My packages include the source code and the pre-compiled binary. Each user is free to either install the binary (for convenience reasons) or compile from the open source.

It is my personal opinion that the documentation for libpruio could use A LOT of work.

Aren’t you the same William Hermans who wrote this and the following posts, ten month ago? Didn’t I generate a PDF version of the documentation and sent it to you, in order to get your help on improvements? Nothing came back, yet. Are you now passing criticism on the progress of your own work?

BR

Hey William, thanks for your statements. (In bad mood again?)

Am Mittwoch, 30. September 2015 22:51:44 UTC+2 schrieb William Hermans:

I also do not feel that the whole library is open enough. Last I looked, one had to download a pre-compiled binary in order to make it work. This is not open source, which is big on many peoples mind.

Where did you find that? My packages include the source code and the pre-compiled binary. Each user is free to either install the binary (for convenience reasons) or compile from the open source.

It is my personal opinion that the documentation for libpruio could use A LOT of work.

*Aren't you the same William Hermans who wrote [this](https://groups.google.com/d/msg/beagleboard/CN5qKSmPIbc/nF1I7mNsvRsJ) and the following posts, ten month ago? Didn't I generate a PDF version of the documentation and sent it to you, in order to get your help on improvements? Nothing came back, yet. Are you now passing criticism on the progress of your own work?*

So why does this have to be about me ? Did you ever stop to think that maybe I tool one look at the documentation, and decided Idid not want to have anything to do with it ? I never even saw a PDF . . .

Gentleman,
I know I am in no capacity to say anything to both of you coz you both are great in own field. So I just want to request you that, please calm down.

and

Sorry I was busy whole day so couldn’t experiment what you suggested, TJF . But I will do it now and will post my response or queries.

but please Calm down…

Agreed.

Here you go Rathin, something to experiment with in the future. http://www.embeddedhobbyist.com/2015/10/beaglebone-black-adc-getting-started/

I need to edit the post and add the packages needed in order to compile the demonstration executable with gcc, but that is not too much of a hurdle. sudo apt-get install build-essential should take care of that.

Cool, Thanks a lot, William…!!

And one good news, first of all for me (of course) but for you and TJF as well. Its that I talked with my professor and we have agreed that its ok for now if our sampling rate is low around 1.2 KHz or so no hassle of external ICs and stuff at least for now… later on I can refine + Update my implementation as I gain momentum… :slight_smile:

So yeah, I will try out your steps and let you know, but I have one assignment hence bit stuck with it… please give me a day to try out…

Sincerely,
Rathin

Well, using the ADC from userspace as I’ve shown in that post should be able achieve ~3k samples a second. Using Continuous mode, I’ve read up to around 10k.

Also, I happened upon DR Molloy’s companion site for the “exploring the Beaglebone” book

, and noticed he demonstrates using a couple of different external ADC’s through the PRU’s. One @100k, the other at ( I think he said ) just above 1msps. Where then the PRU’s were approaching their max speed I guess. Anyway, it’s neat to read about, but for me, I think userspace one-shot mode will be plenty. Even when experimenting with MPPT charge controlling on our solar system here.