Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ADC Read #1

Open
kjplor opened this issue Sep 23, 2015 · 11 comments
Open

ADC Read #1

kjplor opened this issue Sep 23, 2015 · 11 comments

Comments

@kjplor
Copy link

kjplor commented Sep 23, 2015

Hello Rafael,

I am interested in using your library to read the ADC pins on a beaglebone. I have the library completely built and it compiles code correctly. The problem I am running into is that although the beaglebone_pruio_message has the right adc_channel its value seems to be floating and does not correspond to the value in /sys/devices/ocp.3/helper.12/AIN0. I am not currently using the analog multiplexer if that could be causing it but the on board ADC pins are sufficient for my needs. I have been troubleshooting this issue extensively and I just can’t figure it out. Any help or advice on what might be causing the issue would be greatly appreciated. I know I am asking a lot but either way I am grateful you have shared this library publicly.

This is the code I am running that reads a floating ADC value.

#include <iostream>
#include <string>
#include <stdlib.h>
#include <stdio.h>
using namespace std;
#include "SimpleGPIO.h"
extern "C"
{
  #include "beaglebone_pruio.h"
  #include "beaglebone_pruio_pins.h"
}

int LED1GPIO = 47, LED2GPIO = 46, LED3GPIO = 27 , LED4GPIO = 65;
extern "C" int read_ADC_by_PRU(int i); //function definition below main
int main() {

  gpio_export(LED1GPIO);
  gpio_set_dir(LED1GPIO, OUTPUT_PIN);
  gpio_set_value(LED1GPIO, HIGH);
  sleep(1);
  int output = read_ADC_by_PRU(0);
  sleep(1);
  cout << "The reading is " << output << endl;
  gpio_set_value(LED1GPIO, LOW);
}

extern "C" {
  int read_ADC_by_PRU(int i) {
    beaglebone_pruio_start();
    beaglebone_pruio_init_adc_pin(i, 12);
    beaglebone_pruio_message message;
    beaglebone_pruio_read_message(&message);
    printf("is GPIO:%i gpio_number:%i\nADC %i: %i \n", message.is_gpio, message.gpio_number, message.adc_channel, message.value);
    beaglebone_pruio_stop();
    return message.value;
  }
}
@rvega
Copy link
Member

rvega commented Sep 24, 2015

Matthew (@kjplor ), The problem might be that you are not waiting for beaglebone_pruio_messages_are_available() to return 1 before calling beaglebone_pruio_read_message(). You need to do this because the library's PRU code puts the sampled data from the ADCs in a ring buffer and the correct way to read the ring buffer from your code (ARM) is something like:

beaglebone_pruio_message message;
while(beaglebone_pruio_messages_are_available()){
   beaglebone_pruio_read_message(&message);
   // Do something with message...
}

However, it is strange that you are getting any value at all and that it's different from the one in
/sys/devices/ocp.3/helper.12/AIN0. How are you driving the ADC0 pin? Can you post the output of your program?

I think the BBB software has been updated since the last time I used the library and something might have changed. I'll have time in the next couple of days to look into this. Let me know if the code change I'm suggesting works or not.

@kjplor
Copy link
Author

kjplor commented Sep 24, 2015

To drive the ADC pin I am putting the 1.8V ADC reference pin(P9_32) pin into a voltage divider and reading across that. The signal being read is 900 mV DC. The AIN0 file seems to be in mV whereas the PRU reads between 0-4095. My updated code is listed below. It seems to sometimes read the right value but it still does not not read consistently. Also what number of bits are you supposed to init the ADC pin with? In your example you used 7 but the numbers seems more reasonable with 12 bits. Thanks for the feedback.

#include <iostream>
#include <string>
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
using namespace std;
extern "C"
{
  #include "beaglebone_pruio.h"
  #include "beaglebone_pruio_pins.h"
}

int read_ADC_by_PRU(int i); //function definition below main
int main() {
  sleep(1);
  int output = read_ADC_by_PRU(0);
  sleep(1);
  cout << "The reading is " << output << endl;
}

int read_ADC_by_PRU(int i) {
  beaglebone_pruio_start();
  beaglebone_pruio_init_adc_pin(i, 12);
  beaglebone_pruio_message message;
  int looping = 1;
  int value = 666;
  while(looping) {
    while(beaglebone_pruio_messages_are_available() && looping == 1) {
      beaglebone_pruio_read_message(&message);
      value = message.value;
      //printf("ADC %i: %i \n", message.adc_channel, message.value);
      //beaglebone_pruio_stop();
      looping = 0;
    }
  usleep(1000);
  }
  return value;
}

Example Outputs (using 12 bits-Duplicate readings removed to show spread)
root@beaglebone:/usr/Scanner/beaglebone-pruio/cpp-example# ./ReadC1
The reading is 853
root@beaglebone:/usr/Scanner/beaglebone-pruio/cpp-example# ./ReadC1
The reading is 1023
root@beaglebone:/usr/Scanner/beaglebone-pruio/cpp-example# ./ReadC1
The reading is 340
root@beaglebone:/usr/Scanner/beaglebone-pruio/cpp-example# ./ReadC1
The reading is 510
root@beaglebone:/usr/Scanner/beaglebone-pruio/cpp-example# ./ReadC1
The reading is 682

@rvega
Copy link
Member

rvega commented Sep 25, 2015

I can't spot anything weird in your code except you are not calling beaglebone_pruio_stop(). What are your compiler options? I'll try to run your code to see if it works here. I'm not too familiar with using C libraries in C++.
Also, did you compile the library yourself or did you use the binaries in the git repo? Did you compile the PRU part as well?

@rvega
Copy link
Member

rvega commented Sep 25, 2015

Did you try compiling and running c-example program in the repo? Let's see if that one works for you before getting into your code and the C++ compiler. You can modify the example a little bit to only read the ADC0 pin. I'll be available for the next 3 or 4 hours if you want to chat.

@kjplor
Copy link
Author

kjplor commented Sep 25, 2015

I was testing with and without pruio_stop() which is why it was commented out. I compiled the library myself. I have the vendors folder set up as you described. I compiled and ran your example code which outputs ADC6 over and over again but I think that is because I don't have the multiplexer in place. I changed it to read ADC2 instead and that fixed the endless output but finished never gets set to 1 so the code never completes. More concerning to me is the numbers being read don't make much sense to me.

(Output from example.c)
P9_13: 0
P9_11: 0
ADC 0: 3
ADC 6: 45
ADC 6: 46
ADC 6: 45

(Output after change)
P9_13: 0
P9_11: 0
ADC 2: 4
ADC 0: 31
ADC 0: 42

@rvega
Copy link
Member

rvega commented Sep 25, 2015

The way the library works is you get a new message whenever the value in the ADC changes. Electrical levels at the ADC input will always be a bit noisy so you'll get the "endless" output you describe.

If the numbers being output are similar, then the reading is probably fine. If you lower the number of bits, the 12 bit ADC reading will be truncated in the PRU code and the output of the example program will be more stable (less changes in the truncated value equals to less messages arriving to your code).

In other words, if you change the example program's main function to only read one ADC channel and you set the number of bits to 12, you should see a continuous output of numbers that are similar to each other. If you drive the ADC pin to 0v you should see numbers close to 0; if you drive the pin to 1.8V, you should see numbers close to 4095.

Also, if you are not using the analog mux, you can still use ADC6 but it will have a higher sample rate than ADC0 to 5. You can take a look at pru0_main.c to figure out what the sample rate is (or ask me to do it, I have bad memory :)).

Sooo, if you see an output like the following and you can see the average of the values change as you change the input voltage, it's working fine.

ADC 0: 45
ADC 0: 46
ADC 0: 45
ADC 0: 44
...

I remember having trouble when debugging the library if I didn't call the stop routine so I think you should call it. In the example program, when you hit Ctrl+C, the program will receive a SIGINT signal, the while loop will end and the stop routine will be called.

If you don't need this behavior and all you want is a one shot value of the ADC, reading /sys/devices/ocp.3/helper.12/AIN* should suffice, right? I built this library to achieve the lowest possible latency and to have a well known and stable sample rate when reading the ADCs. I use it for user interaction with electronic musical instruments. Everything has to be on time so you can play rhythmically.

@kjplor
Copy link
Author

kjplor commented Sep 25, 2015

Yeah I wish I could just read the AIN files in helper. The reason I am trying to use a library is the fact that I need to read 4 AIN pins. Whatever driver is used to do the actual reading of the AIN pins has a bug in it that causes an underflow error after switching which pin you are reading a given number of times. So how are you turning your reading into a voltage? I thought it was as simple as multiplying by (1800/4095) but for outputs as low as 44-46, when the pin is seeing 600 mV DC, it seems a custom calibration curve would be more appropriate.

@rvega
Copy link
Member

rvega commented Sep 25, 2015

I don't need to turn values into voltages for my use case. I guess you could easily implement the calibration curve as a lookup table either in PRU (library code) or in ARM (library or app code).

@rvega
Copy link
Member

rvega commented Sep 25, 2015

With the clarifications above, is the example program and your program working as expected?

@kjplor
Copy link
Author

kjplor commented Sep 25, 2015

I just don't trust the spread of the readings when the pin is seeing a set DC signal. That being said your explanations have been very helpful and if I figure out the source of the variance I will let you know.

@rvega
Copy link
Member

rvega commented Sep 25, 2015

You're right about not trusting the range. Take a look at https://github.com/outer-space-sounds/beaglebone-pruio/blob/master/library/src/pru0_main.c#L385. The bits value is hardcoded to 8 in the PRU code. I don't know why or when I did that. You can remove that line if you want the full 12 bits. I opened #2 to make sure I adress this in the next few days.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants