8 ADC input @20 KHz

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…

No big hurry. I was just putting that out there in case you wanted to experiment with it. I think for your end goal, needing 20Khz, what I propose is a dead end. However I still think it is a good learning experience, and perhaps useful for other things. 2.5k-3k samples a second is still pretty good. Just not for your end goal.

@William

TJF, knock it off already. So far, I’ve been really nice to you, when I really did not have to. If you want to continue this discussion feel free to mail me directly, and stop sidetracking this post.

Hi, TJF,

“New agreement” in a sense that I discussed and we are OK (for now) to study low frequency transients, hence it would be OK if we sample at low rate.

I can not say that I have to start from scratch coz I am at “scratch” level right now :frowning: . I am in the beginning of this whole thing and I have sort of 20 days to finish it.

No I dont have my “monitor” code ready because I was depending upon the samples which I would get from the system, That would decide my monitoring/analysis method- like do I require software filter to remove noise? Do I need a batch mode operation or a sample by sample operation ( depending upon the way I receive the ADC input , say your io_input example program used to give me separate samples where as your new RB programs gives me a whole chunk of data!!)

So,yeah I am still starting off, though I have very less time I am still at the “start” (I wasted (or invested) almost 30-35 days just to study different things -what is PRU- PRU assembly coding, - BeaglelLogic, libpruio etc… )

Hi TJF,

I had a small gap so I tried your new code, and Its giving me “config fault: sample rate too big”.

I tried changing tSamp, to 2000 but still it doesn’t work So what changes should I make? and one another query how to extend the same code of 8 ADCs? just to change NoStep??

Regards,
Rathin

Hi Rathin!

Hi TJF,

I had a small gap so I tried your new code, and Its giving me “config fault: sample rate too big”.

I tried changing tSamp, to 2000 but still it doesn’t work So what changes should I make?

tSamp is the number of samples in the file. The final file size will be tSamp * NoStep * 2.

Your error message is about the sampling rate, it reaches a certain limit.

There’s a miss-configuration in version-0.2 in file pruio_adc.bas. The limits for the sampling rate get computed to rigid. You can either use much slower sampling rates, as a workaround for now to get started) like

`
const uint32 tmr = 50000; //!< The sampling rate in ns (50000 → 20 kHz).

`

or fix the code and recompile. Therefor install the FreeBASIC compiler and adapt file pruio_adc.bas in function AdcUdt.configure() around line 133 it should be

`
IF Samp < 2 THEN ’ IO mode
Samples = 1
TimerVal = 0
ELSE
IF r < 1 THEN .Errr = @“no step active” : RETURN .Errr
Samples = Samp * ChAz
IF (Samples SHL 1) > .ESize THEN _
.Errr = @“out of memory” : RETURN .Errr
d = (d * (Conf->ADC_CLKDIV + 1) * 1000) \ 24
IF Tmr <= d ORELSE Tmr < 5000 THEN _
.Errr = @“sample rate too big” : RETURN .Errr
Value = .ERam
TimerVal = Tmr
END IF

`

Then compile and install the new version.

``

and one another query how to extend the same code of 8 ADCs? just to change NoStep??

As mentioned in the code:

const uint32 NoStep = 3; //!< The number of active steps (must match setStep calls and mask).

You have also to adapt the mask variable and the calls to pruio_adc_setSteps()

`
const uint32 NoStep = 8; //!< The number of active steps (must match setStep calls and mask).

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;}
if (pruio_adc_setStep(io,12, 3, 0, 0, 0)){ // step 12, AIN-3
printf(“step 12 configuration failed: (%s)\n”, io->Errr); break;}
if (pruio_adc_setStep(io,13, 4, 0, 0, 0)){ // step 13, AIN-4
printf(“step 13 configuration failed: (%s)\n”, io->Errr); break;}
if (pruio_adc_setStep(io,14, 5, 0, 0, 0)){ // step 14, AIN-5
printf(“step 14 configuration failed: (%s)\n”, io->Errr); break;}
if (pruio_adc_setStep(io,15, 6, 0, 0, 0)){ // step 15, AIN-6
printf(“step 15 configuration failed: (%s)\n”, io->Errr); break;}
if (pruio_adc_setStep(io,16, 7, 0, 0, 0)){ // step 16, AIN-7
printf(“step 16 configuration failed: (%s)\n”, io->Errr); break;}

uint32 mask = 255 << 9; //!< The active steps (9 to 16).

`

BR

Hi TJF,

Finally I tried your code, with reduced sample rate ( i preferred not to recompile) I got file output.0 & ouput.1 but they are binaries!! I am not able to read them with any format or in any text-editor. Can you suggest how to read them?

Once again thanks a lot for tips!! I

Hi Rathin,
just to let you know: The BBB ADC’s can sample at 1.6 MHz. That is, if you multiplex the ADC on 8 inputs, each one of them can sample at 200kHz. I am not familiar with user-friendly libraries like libpruio, so I cannot tell you where they lose the time. But technically (e.g. by writing the assembler instructions), 200 kHz is definitely possible, so you could upgrade your project at a later moment without changing the hardware. The price to pay (at the moment) is a little more customized code. But seeing that people struggle already at 20kHz just hurts my eyes :wink:
Lenny

here is a thread talking about it, in which you can also find my code example among other info.

https://groups.google.com/forum/#!searchin/beagleboard/fast$20ADC/beagleboard/3AFiCNtxGis/RiWxHDiOWnMJ

In my case, I’m going to bitbang the I2C to work with the ad7997 to sample 8 analog input. I don’t have the choice the 8 input of the processor is already used for something else.

This will not be that difficult because the code to bitbang the I2C is available there :
https://github.com/Rose-Hulman-ROBO4xx/1314-BeagleBone-Quadcopter/blob/master_rev2/code/ControlAlgorithm/quadcopter_apps/imu/imu.p

My only problem is that for the moment the pru is not working with the kernel 4.1 . I will have to test that on the kernel 3.8 :frowning: .

Micka,

Hi William,

Finally I got times to try out your post and have to admit, very precise instructions!! :slight_smile: coming to technical point, I have following queries.

  1. This program samples only 1 ADC correct? involtage0_raw To extend it for all 7 channels woudl I have to create 7 such pointers, correct?
  2. this is Ti rt kernel, is it same as TI-RTOS? and if not, where can I find it’s APIs?
  3. This kernel has completely new structure, so now my PRUs are completely unusable :slight_smile: any suggestions? initially it was accessible by “/sys/devices/bone_capemgr.*/slots” which now doesn’t exist!!
  4. Is your existing code able to reach 3K sample speed? if not can you suggest changes for that?

Sorry for such a long list of queries…

Sincerely,
Rathin :slight_smile:

Lenny,

Thanks for dropping by!! yes I am aware of the thing you are saying, actually your post (& code ) was the post because of which I decicded to use BBB and PRU for my purpose :slight_smile:

but to be frank, Assembly coding is bit intimidating for me right now, I invested almost 20 days to study PRU reference guide but couldnt start a bit!!
another bummer was how to transfer data from PRU to userspace,
If you can guide me precisely, I will be more than happy to walk on that path…!! :slight_smile:

1) This program samples only 1 ADC correct? involtage0_raw To extend it for all 7 channels woudl I have to create 7 such pointers, correct?

Technically, yes. The pointer is actually a string pointer for the given file pah. However, you could use a for loop, and generalize the string, using the for loop to “inject” 0-7. Look into the function sprintf(), and while at it google “sprintf() dangers” or you could just red this post: http://stackoverflow.com/questions/3662899/understanding-the-dangers-of-sprintf

2) this is Ti rt kernel, is it same as TI-RTOS? and if not, where can I find it’s APIs?

No. For the Linux API’s, you just need to become familiar with std libc / POSIX functions. Then google. Each libc POSIX function when you need more information, etc. I actually goolge A LOT when it comes to API calls, as I do not always remember exact details. Anyway, TI-RTOS is potentially problematic for this hardware. First I’m not even sure it would run on this hardware. Second, you would have to write much functionality yourself. Besides you could use just plain Linux to do what you want, using the PRU’s. I’ve read at least one blog post where a person was achieving 14MB /s + data using the PRU’s + a non rt kernel. Yes, that’s 14 Megabytes a second.

3) This kernel has completely new structure, so now my PRUs are completely unusable :slight_smile: any suggestions? initially it was accessible by "/sys/devices/bone_capemgr.*/slots" which now doesn’t exist!!

Yes, the PRU’s do not work on this kernel. I believe I mentioned this before, but in case I did not this is why I recommended if you experimented with this to keep your old sdcard as well. However, and with with that said. Currently I am working on a similar non TI kernel that does support the PRU. That, and I WILL be using the PRU to access the on chip 200k SAR module. Not sure how long this will take me to get working though. Anyway, I have interest in this as well. Remember one of my electronics interests is power electronics :wink: So using the ADC, and a PWM could be used as a control for a SEPIC( or similar ) DC-DC power converter. If not, well then, it’s still useful for testing.

4) Is your existing code able to reach 3K sample speed? if not can you suggest changes for that?

Reload my blog post and read the update. ~2960 samples a second seems to be max for a single channel, in one-shot mode. This also uses ~77% CPU, so there is not much room for improvement. One thing that I did consider, was using fork(), with some form of timing, and multiple channels. Also note that my code has changed a little. Specifically . . .

if(len == -1){
close(fd);
continue;
}

This enables the code to run continuously without problems related to the device being busy. So in effect you could remove the while loop check, and just run it in an infinite loop. If you want to know how it works. I briefly describe that on my blog post in the update part at the bottom.

So . . . I’ve not done this yet, but I think one might be able to achieve between 3-4k a second samples using multiple processes, on multiple channels, and with tight timing. I’ve done some reading, and this seems to be inline what others have achieved in the past. The biggest hindrance will be the CPU in this case however.

Using continuous mode on the ADC should be able to improve the situation somewhat. But according to what I’ve read. ~10k samples a second while using sysfs will be the maximum. I’ve read that mmap() can improve this considerably. But honestly, and for the moment this is over my head. I know mmap() fairly well, but in this case, I do not know what address should be mapped through /dev/mem/, or how I would get the data out of the ADC running in continuous mode. I do think that using mmap() + /dev/mem/ could come close to the maximum theoretical limit of the 200k SAR module though . . . But this is just a hypothesis based on various things I’ve read.

Hi Rathin!

wow, my math was way off.

My first experiment was actually 4997.334754797441 samples a second. Using this new kernel I’m using now, with all the printf()'s commented out is:

debian@beaglebone:~$ time ./test

real 0m50.929s
user 0m0.340s
sys 0m50.450s

For 300,0000 iterations. So . . .5890.55351567869 samples a second.

With the printf()'s back in place:

. . .

4015 4009 4009 4013 4007 4011 4015 4004 4004 4013
real 0m57.302s
user 0m0.940s
sys 0m52.710s

So . . . 5235.419357090503 samples a second.

Dear William,

Thanks for the detailed reply…!

  1. Thanks for the sprintf tip, I will work on it and put a code here…!!

  2. 14 MB/S data rate, yes, I have read that post :slight_smile: that was one of the reason I got impressed by BBB & choose…!! but thing is over there an external ADC + buffer is used…!!

  3. Regarding kernel question , sorry I felt silly after asking it. I asked it because I wanted to use system time & Ethernet socket so I thought there would be some separate API. (just like Xenomai, it has its own command)

  • Oh you are in to Power Electronics… wonderful…! yeah this can be used in converters but interesting application would be sensor-less BLDC motor controller… or HIL recorder-player!!
  1. I tried with while(1) and it ran perfectly. Now I will try changing to continuous mode as well as the no of ADC in to the program and will report back to you…!!

Thanks for the kick start, It is of immense help and yes I have understood since the beginning that Google is our BEST friend when working on something new…!! though my results are not as accurate as ur’s but working on it… :slight_smile:

Once again thanks… will post back my new code, soon.

Rathin

Dear TJF,

Sorry to bug you with a silly question, I thought being a binary it must have some specific encoding rel. to library hence I asked it. I didnt knew it was lack of knowledge. I am sorry…!!

I Have figured out the way to read binary (code pasted bellow for others;) but I have a doubt in it that I have lot of Zeros & negative readings as well
Is it because of my decoding error or is it the samples themselves missing.

Thanks a ton…!!

`
#include<stdio.h>
int main()
{
FILE *fp = NULL;

short result[100];
int i;

fp=fopen(“output.0”, “w+”);
rewind(fp);
if(fp != NULL)
{
fread(result, sizeof(short), 100 /# of samples/, fp);
}
else
return 1;

printf(“Result\n”);
for (i = 0; i < 100; i++)
printf("%d = %d\n", i, (int)result[i]);

fclose(fp);
return 0;
}

`

4) I tried with while(1) and it ran perfectly. Now I will try changing to continuous mode as well as the no of ADC in to the program and will report back to you…!!

Thanks for the kick start, It is of immense help and yes I have understood since the beginning that Google is our BEST friend when working on something new…!! though my results are not as accurate as ur’s but working on it… :slight_smile:

Once again thanks… will post back my new code, soon.

If you get continuous mode working I’d be interested in seeing the code. Might even be able to optimize it some for you :wink: But I know someone on another forum who is interested in continuous mode. I told him that I am more interested in getting the PRU’s involved, but might get around to it someday. I know compared to PRU + ADC it will be slow. But if you can get continuous mode working from sysfs, you only need one open(), and close() call for the lifetime of the application for each file path. Which is to say that open(), and close() will no longer have an impact on the application run speed. Then you only need worry about OS latency, and the efficiency of your code . . .

You know, a couple friends from different countries, and I have proven that google results vary from country to country. So maybe your results are skewed based on your locale some ? There is a way you can specify which server google uses when you search, but I forget the details. Well, aside from using a web proxy :wink: Have fun !

Rathin, on a side note, I did get the pru’s working on the kernel Im using now which is:

debian@beaglebone:~$ uname -a
Linux beaglebone 4.1.9-bone-rt-r16 #1 Thu Oct 1 06:19:41 UTC 2015 armv7l GNU/Linux

The pru example code seems to work fine too . . .
debian@beaglebone:~/am335x_pru_package/pru_sw/example_apps/bin$ sudo ./PRU_memAcc_DDR_sharedRAM

INFO: Starting PRU_memAcc_DDR_sharedRAM example.
INFO: Initializing example.
INFO: Executing example.
INFO: Waiting for HALT command.
INFO: PRU completed transfer.
Example executed succesfully.

But man, lot’s of jumping through hoops to get to here. I had to piece together from all over the web, so you can bet once I’m ready I will make a blog post on it. If for no one else, for myself. I still want to write a simplified “hello world” example. Blinking USR0 using the PRU . . . After that, then onto using the on chip ADC.

Ah!

ADC Driver Limitations

This driver is based on the IIO (Industrial I/O subsystem), however this is the first release of this driver and it has limited functionality:

  1. No HW trigger Support. Currently only supporting software trigger.
  2. Limited number of samples in continuous capture mode. (Only 1528 samples per capture)
  3. Limited maximum sample rate in continuous mode: 8K samples / second.
  4. Simultaneous capture on multiple ADC channels is not supported. Currently only supports continuous capture on a single ADC input channel at a time.
  5. “Out of Range” not supported by ADC driver.

http://processors.wiki.ti.com/index.php/AM335x_ADC_Driver’s_Guide