8 ADC input @20 KHz

But that page claims it's obsolete and directs to the new page:

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

which seems to list fewer limitations.

Hi!

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…!!

Never mind!

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.

As I said, I’m no C expert. Here’re my comments:

  • I’d fopen() for read.

  • I’d check the return value from fread() in order to avoid missreadings (= interpreting memory garbage).

  • Most important: since Adc->Value is an Uint16*, the result array has to get declared as unsigned short result[100];`

    `

Here’s code I use (FB syntax):

`
VAR fnam = “output.0”, fnr = FREEFILE
IF OPEN(fnam FOR INPUT AS fnr) THEN
?"Cannot open " & fnam
ELSE
DIM AS USHORT v
VAR cc = 8, c = 0, i = 0
WHILE NOT EOF(fnr)
c -= 1 : IF c <= 0 THEN i += 1 : c = cc : ? : ? i & ": ";
GET #fnr, , v
? v,
WEND
CLOSE #fnr
END IF

`

It reads the complete file and formats the output in 8 columns (cc = 8).

BR

Dear William,

As Prezemek suggested its an older version of driver user guide!! though the new version doesn’t enlist the limitation at all except 1!! it’s “Limitless”… :slight_smile:
I am currently studying continuous mode. stuck with few hurdles, I will let you know once I get some lead.

Sincerely,
Rathin

PS: Yes, there are lot of “jumping through hoops”, yet you were able to manage it, I couldnt :frowning: I got so confused and clueless… though I feel assembly language would be the most easiest way to deal with PRUs even after considering the efforts in writing the assembly code. what do you say?

mmap() should max out the ADC’s, but I’m going to do it just because I can. So, ADC, to PRU, to DDR, plus userland C to mmap() the region of DDR is very similar. What is not similar and in favor of the PRU is less CPU load, and determinism.

Rathin,

Anyways, This morning I decided go ahead and test continuous mode using the ti user space driver. After much testing and fooling around I’ve come to the conclusion, and perhaps incorrectly. That this userspace driver is dog slow. How I’ve come to this conclusion is as follows.

With slightly modified code from my one-shot example, I was able to achieve ~15k samples a second right from the get go. Thinking I could improve on this somewhat I was experimenting with something ( sorry do not know exactly what ), and got a figure of 35k samples a second. After this, I started to attempt to control read by using a simple timing mechanism. Both usleep(), and nanosleep() introduce a large amount of latency into the application. So neither of those will work. I have not tried using ualarm() yet, and I’m kind of hopeful, but . . . I’m thinking it depends on syscalls so . . .will likely not work either.

So after experimenting with couple timing functions, I decided to check what len = read() was collecting. To my surprise, it was returning an awful lot of -1’s. SO I figure hey, I’ll just check len, and continue like with the old app. Well it worked, except sample rate dropped into the toilette. A “whopping” 300-400 samples a second. This is why I think the ADC userspace driver is dog slow.

Anyway, I did full blast testing, no timing, just 100% loop, read, printf() every 100,000 iterations - For 2 million total iterations. I get somewhere between 800k-900k samples a second. Of course, much of that data is redundant, and I did a rough guess count, and figured it was roughly 35k / second unique values. CPU is pretty much pegged at 95-99% CPU like this though . . .

Another thing to keep in mind with my testing data. What I’m testing could actually be faster. I do not have a voltage applied to the ADC. I’m just reading the floating pin values off channel 0 . . . Maybe I can hook up an LED to AIN0 to AIN_ground, and aim it at the blinking USER LEDs to get some variation ? heh.

Anyway I need to take a little break, then I’m back at it.

Hello William,

So you were able to run the continuous mode driver? I am on to it since 1.5 day… You are talking about the driver program that is “generic_buffer.c” am I correct? and your 800k - 900k samples are for single channel correct, so in that case for 8 channels it would be 100K which is really exciting!! :slight_smile:

btw you are using RT kernel have you tried giving priority to the program while running? it might improve the results…

Your results are exciting me… please I will make my program work somehow and paste it here. Please dont paste your code yet… let me figure out my way and then if i face problem, you can guide 0:-).

Rathin

921234.4541685859 Samples a second exactly. You need to understand though. Many, many samples are the same value. At this time I was sampling just one channel. Late last night before bed, I was sampling all 7 available channels, and was noting that some channels were putting values into the buffer more often than others. It was nothing concrete, and almost seemed random. So I implemented reading the channel ID for each channel, and started sampling by ID. Samples / second went way down

as a result, but now I have accurate 1-7 samples in order. Anyway, I think this has to do with ADC data averaging, but there is no way that I know of through userspace to set averaging. I think if I disable averaging, the buffer should be populated more consistently. But again . . . this is a guess. Also, I’ve read that one can change the clock multiplier of the ADC too. Default is 0x7, and it can be set to 0x0. From a 24Mhz source. But maybe this is a mmap() or PRU thing ?

With mmap() I should be able to manipulate the ADC registers just like how the PRU’s do things.

Anyway, I think I’ve shown that Linux can keep up with more than 200k / second samples.

Now, to find a way to make the ADC keep up :wink:

So Rathin, let me give you a hint:

http://processors.wiki.ti.com/index.php/Linux_Core_ADC_User’s_Guide#Beaglebone.2FBeaglebone_Black
and
http://elinux.org/images/6/65/Spruh73c.pdf#page=1573&zoom=auto,0,719

Is all the information I needed to get all this working. So, in fact should be all you need as well. However, I think you might be struggling more with the C aspect . . .

Hi,
Oh, magnificent…!!

Yes you are correct I am facing problem in C…!! actually this link depicts exactly my state…
http://c.learncodethehardway.org/book/introduction.html
specially the last paragraph in “Introduction” section and 1st in “Core competence” section :slight_smile:

and btw two small queries,

  1. I have gone through your links, so, did you recompile the kernel? with those modules ON…?
  2. your this result is for single shot mode right?

Once again thanks for a spell of motivation.

Rathin

#1 No, the module is already compiled for the image.

#2 No, this is continuous mode with all 7 configurable channels running( 8 including AIN7 ), and just blasting the data to screen. No ordering, not checking anything. There are many MANY redundant reads.

By the way, one thing I did note. Remember me saying printf() was not slowing anything down( much ) using sysfs, and the iio driver ? Well, using mmap() and then printf() to display the data. Slows the sample rate by 50%+. Specifically newlines → “\n” seem to be the biggest culprit.

Anyway, that just goes to show how much faster using mmap() through /dev/mem is. Now . . . I need to figure out a good way to display, or otherwise view the output data without slowing down the whole process . . . Maybe one huge array that get’s blasted to screen, or a file all at once ? Shrug

Okk…!!
#1 So I will keep using the image which you have shown in your blog post(for now) for my further development
#2 Ok, for that I am not worried much for now! as for now I WANT data, and I will be implementing a filter maybe in second stage once I get this thing working.

Yes, you should take a break, I will post here once I have something to show!! Though I wont go in mmap for now, I will stick to my singleshot & continuous mode implementation.

Thanks a lot for help…

Rathin

Couldn’t step away until I did this test but . . .

debian@beaglebone:~$ time sudo ./test > output.txt

real 0m1.059s
user 0m0.370s
sys 0m0.030s

Data is formated as such: channel:data That’s 200k iterations( nearing 200k samples / second !!!) with A LOT of data that looks like this:

0:3731 2:3157 0:2115 6:3248 1:0520 0:3619 2:1464 4:0796 3:0872 6:2609
1:0831 6:3612 2:0141 1:3921 3:1488 0:0243 5:2981 3:1685 2:1118 5:0523
1:3068 5:2318 4:0123 3:0532 3:3336 1:1599 1:2541 0:3731 2:3157 0:2115
6:3248 1:0520 0:3619 2:1464 4:0796 3:0872 6:2609 1:0831 6:3612 2:0141
1:3921 3:1488 0:0243 5:2981 3:1685 2:1118 5:0523 1:3068 5:2318 4:0123
3:0532 3:3336 1:1599 1:2541 0:3731 2:3157 0:2115 6:3248 1:0520 0:3619
2:1464 4:0796 3:0872 6:2609 1:0831 6:3612 2:0141 1:3921 3:1488 0:0243
5:2981 3:1685 2:1118 5:0523 1:3068 5:2318 4:0123 3:0532 3:3336 1:1599
1:2541 0:3731 2:3157 0:2115 6:3248 1:0520 0:3619 2:1464 4:0796 3:0872
6:2609 1:0831 6:3612 2:0141 1:3921 3:1488 0:0243 5:2981 3:1685 2:1118
5:0523 1:3068 5:2318 4:0123 3:0532 3:3336 1:1599 1:2541 0:3731 2:3157
0:2115 6:3248 1:0520 0:3619 2:1464 4:0796 3:0872 6:2609 1:0831 6:3612
2:0141 1:3921 3:1488 0:0243 5:2981 3:1685 2:1118 5:0523 1:3068 5:2318
4:0123 3:0532 3:3336 1:1599 1:2541 0:3731 2:3157 0:2115 6:3248 1:0520
0:3619 2:1464 4:0796 3:0872 6:2609 1:0831 6:3612 2:0141 1:3921 3:1488
0:0243 5:2981 3:1685 2:1118 5:0523 1:3068 5:2318 4:0123 3:0532 3:3336
1:1599 1:2541 0:3731 2:3157 0:2115 6:3248 1:0520 0:3619 2:1464 4:0796
3:0872 6:2609 1:0831 6:3612 2:0141 1:3921 3:1488 0:0243 5:2981 3:1685
2:1118 5:0523 1:3068 5:2318 4:0123 3:0532 3:3336 1:1599 1:2541 0:3731
2:3157 0:2115 6:3248 1:0520 0:3619 2:1464 4:0796 3:0872 6:2609 1:0831
6:3612 2:0141 1:3921 3:1488 0:0243 5:2981 3:1685 2:1118 5:0523 1:3068
5:2318 4:0123 3:0532 3:3336 1:1599 1:2541 0:3731 2:3157 0:2115 6:3248
1:0520 0:3619 2:1464 4:0796 3:0872 6:2609 1:0831 6:3612 2:0141 1:3921
3:1488 0:0243 5:2981 3:1685 2:1118 5:0523 1:3068 5:2318 4:0123 3:0532
3:3336 1:1599 1:2541 0:3731 2:3157 0:2115 6:3248 1:0520 0:3619 2:1464
4:0796 3:0872 6:2609 1:0831 6:3612 2:0141 1:3921 3:1488 0:0243 5:2981
3:1685 2:1118 5:0523 1:3068 5:2318 4:0123 3:0532 3:3336 1:1599 1:2541
0:3731 2:3157 0:2115 6:3248 1:0520 0:3619 2:1464 4:0796 3:0872 6:2609
1:0831 6:3612 2:0141 1:3921 3:1488 0:0243 5:2981 3:1685 2:1118 5:0523
1:3068 5:2318 4:0123 3:0532 3:3336 1:1599 1:2541 0:3731 2:3157 0:2115
6:3248 1:0520 0:3619 2:1464 4:0796 3:0872 6:2609 1:0831 6:3612 2:0141
1:3921 3:1488 0:0243 5:2981 3:1685 2:1118 5:0523 1:3068 5:2318 4:0123
3:0532 3:3336 1:1599 1:2541 0:3731 2:3157 0:2115 6:3248 1:0520 0:3619
2:1464 4:0796 3:0872 6:2609 1:0831 6:3612 2:0141 1:3921 3:1488 0:0243
5:2981 3:1685 2:1118 5:0523 1:3068 5:2318 4:0123 3:0532 3:3336 1:1599
. . .

Now I am off for a break.

To screen:
2000000 total iterations
channel 0 samples: 296296
channel 1 samples: 444444
channel 2 samples: 296296
channel 3 samples: 370371
channel 4 samples: 148149
channel 5 samples: 222222
channel 6 samples: 222222
real 0m16.247s
user 0m3.850s
sys 0m3.140s

To file:
2000000 total iterations
channel 0 samples: 296296
channel 1 samples: 444445
channel 2 samples: 296296
channel 3 samples: 370370
channel 4 samples: 148148
channel 5 samples: 222222
channel 6 samples: 222223
real 0m5.768s
user 0m3.650s
sys 0m0.090s

How does ~25684 Samples a second worst case, per channel sound ? Channel 4 there is looking a bit weak. I need to investigate that. Who said 20k samples / second per channel from the Linux side was not possible ? Also, since ssh is eating half the CPU while using printf(), those numbers can be improved. 13.5M in 5 seconds though . . . not too shabby.

By the way, there are 2 FIFO buffers for the ADC. I’m only reading from one. So this is something else I need to look into. Actually there is a lot I need to read up now that I’m able to directly twiddle the ADC’s registers.

Hi,

So during this implementation you are using FIFO buffer that you pointed out?? should I as well use that?? or should I simply read from “/sys/bus/iio/devices/iio:device0/in_voltage4_raw” …?

http://processors.wiki.ti.com/index.php/Linux_Core_ADC_User’s_Guide#How_to_set_it_up

File path is mentioned here. Towards the end. Read everything, not just the command line examples.

OK, so now, I seem to be having issues with the FIFO. Not sure what it is, but I have to tone down my experimentation a bit as I’ve got other things that are of a higher priority. Such is life, but I’m by no means done with this.

Hi William,

Oh, I had already seen that and experimented with it…!!but had forgotten, after watching your link I recollected. I am really sorry for silly question.

Have you experimented with buffer size? is there any optimal value calculation? Would it have any impact on the result, Like if we keep a larger buffer and than directly take that buffer that way it would be faster? I have currently kept 1k.

And yes, Priority is a priority!! I though you were on break from BBB,…!! :slight_smile:

Sincerely,
Rathin

Well, the buffer I’m talking about is the ADC buffer. I’ve been looking through others code for PRU → ADC, and have been attempting to translate that. I’m afraid my ASM skills are very lacking for this task( I have not written ASM code in years ). However the constants used in much of the code out there, are the same. So while I do not yet know what LBBO, and stuff liek r0-r31 mean for program flow, I can figure out the addressing very quickly. Not to mention that the TRM has this information too, but the TRM is very terse reading for many things. It’s great for “cherry picking” offsets, but much of the information is not presented in an order that makes the most sense to me. ie, you have to bounce around too much form one place to another in this huge manual . . .

So, I may have to take a break, and get to know the PRU assembly language well before proceeding much further. Which is something I intended on doing anyhow, just not right at this moment. One thing that has me excited here is an idea that came to me last night. Concerning using the PRU’s in a way I’ve not seen anyone else do - yet. Well, I’ve seen mention of others touching on the subject I suppose, but . . . yeah I do not want to let my “secrete” out just yet.

Have you experimented with buffer size? is there any optimal value calculation? Would it have any impact on the result, Like if we keep a larger buffer and than directly take that buffer that way it would be faster? I have currently kept 1k.

Yeah sorry, I’m kind of in my own world here at the moment. Anyway, like I mentioned above I was speaking of the ADC FIFO. As for buffering into system RAM, this is certainly possible, and very likely preferable. This can also be done, very easily, using POSIX shared memory. Potentially, this is a problem, as once the data is in RAM, how do you get it back out for transport. Without using additional CPU cycles, or using the PRU’s ? Not using the PRU’s for this by the way, is a constraint I’ve placed on myself. Just to see if it is reasonably possible. Indeed, I do believe it is possible, but not quite sure how reasonable that possibility is. - Yet.