FilipDominec / rp2daq

Raspberry Pi Pico firmware for universal hardware control & measurement, along with a user-friendly Python frontend
MIT License
27 stars 4 forks source link

ADC impedance is exteremely low #18

Closed epsi1on closed 1 month ago

epsi1on commented 1 month ago

Hi, I was working with the ADC, i just found out the input impedance is very low. when i connected 3v3 to ADC through a 1k resistor, the adc readout is about 3.0v but without resistor it reads ~3.3v. with 10k and 100k resistor the readings are lower respectively. very much like there is a pull down resistor somewhere in the path. After some search just seen this thread which had exactly same problem. Seems the fix for this problem is to initialize the connected pin as input (please check the link above).

Thanks.

FilipDominec commented 1 month ago

Good tip, thanks. Being an active user of rp2daq in a lab I also noticed there is some 30kohm pull down, which is however not a problem when reading the output of a buffering opamp. I will check out the pin config effect in the next weeks.

-------- Původní zpráva --------

    1. 2024 12:03, Ehsan M.A. napsal/a:

Hi, I was working with the ADC, i just found out the input impedance is very low. when i connected 3v3 to ADC through a 1k resistor, the adc readout is about 3.0v but without resistor it reads ~3.3v. with 10k and 100k resistor the readings are lower respectively. very much like there is a pull down resistor somewhere in the path. After some search just seenthis thread which had exactly same problem. Seems the fix for this problem is to initialize the connected pin as input (please check the link above).

Thanks.

— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you are subscribed to this thread.Message ID: @.***>

epsi1on commented 1 month ago

I did some tries with gpio_highz but still same problem.

did try with multiple resistors and this is values:

adcVref ----- RESISTOR ----- GPIO28

RESISTOR (KOhm) V (Adc/4096*3.3)
0.018 3.29
0.075 3.29
0.22 3.28
0.33 3.27
1 3.17
4.7 3.01
10 2.74
33 1.63
51 1.15
75 0.85
100 0.7
175 0.415
390 0.22
499 0.19

Very much like there is a ~28KOhm pulldown at adc pin

FilipDominec commented 1 month ago

Yeah, I can confirm it in my setup. I was going to conclude this is an internal limitation of RP2040, but on page 561 of the RP2040 docs they write:

"The effective impedance, even when sampling at 500ksps, is over 100kΩ, and for DC measurements there should be no need to buffer."

So more research is justified. The only apparent difference from the official ADC example is that they call adc_init() before adc_gpio_init(...). Not sure this makes the difference, and I will have to check this example has higher input impedance at all. Will get back to you soon, I hope.

epsi1on commented 1 month ago

thanks, i was trying to validate official ADC example, successfully compiled it into .uf2 and uploaded to pico. but were not able to see the data from pico, because no COM port appeared on my pc... Do you think the official pico example have low impedance problem as well?!

FilipDominec commented 1 month ago

So connecting a simple kΩ-meter between pin 26 (i.e. ADC0 input) to board ground, I could get following figures:

So your issue is fully reproducible. Then I made an experiment, changing the ADC&pin initialization like this:

    adc_init();
    for (uint8_t ch=0; ch<4; ch++) {
        if (iADC_config.channel_mask & (1<<ch)) 
            adc_gpio_init(26+ch); 
            gpio_set_dir(26+ch, GPIO_IN); // not necessary here?
            gpio_disable_pulls(26+ch); // sets the input into high-z state again 
    }

... et voilà, the pin got some >200MΩ impedance, yet it seems to measure voltage correctly. I will have to test this thoroughly yet, but the problem seems resolved. I learned something new, too. Thanks for reporting.

The commit is 8a678ebf. Since you wrote your oscilloscope app with hard-wired messaging, the binary protocol between rp2daq board and computer has changed several times. If you really wish to continue with your custom C# oscilloscope software, it will require manually patching only the include/adc_builtin.c file of your chosen firmware version, and recompiling/uploading without any further changes to the codebase. Or - you may switch to latest firmware and upload it, but then check carefully your hardwired C# communication routine does not fail in this case.

epsi1on commented 1 month ago

So connecting a simple kΩ-meter between pin 26 (i.e. ADC0 input) to board ground, I could get following figures:

* RP2 just disconnected: **~15 MΩ**

* pristine RP2 without flash program, but powered up: **24.4 kΩ**

* RP2 with rp2daq firmware running, no ADC conversion:  **24.4 kΩ** again

* RP2 with rp2daq firmware running, 50ksps ADC conversion active:  **21.6 kΩ**

So your issue is fully reproducible. Then I made an experiment, changing the ADC&pin initialization like this:

    adc_init();
  for (uint8_t ch=0; ch<4; ch++) {
        if (iADC_config.channel_mask & (1<<ch)) 
            adc_gpio_init(26+ch); 
            gpio_set_dir(26+ch, GPIO_IN); // not necessary here?
            gpio_disable_pulls(26+ch); // sets the input into high-z state again 
    }

... et voilà, the pin got some >200MΩ impedance, yet it seems to measure voltage correctly. I will have to test this thoroughly yet, but the problem seems resolved. I learned something new, too. Thanks for reporting.

The commit is 8a678ebf. Since you wrote your oscilloscope app with hard-wired messaging, the binary protocol between rp2daq board and computer has changed several times. If you really wish to continue with your custom C# oscilloscope software, it will require manually patching only the _include/adcbuiltin.c file of your chosen firmware version, and recompiling/uploading without any further changes to the codebase. Or - you may switch to latest firmware and upload it, but then check carefully your hardwired C# communication routine does not fail in this case.

Thanks, really happy that problem is solved :) Actually it was somehow hard to understand how rp2daq's API works, it is kind of automated. i finally ended up deriving a custom serial class from python's serial and replace it in the rp2daq.py and usb_backend_process.py to see what is going on under the hood. without this reporting serial i was not able to use all functions.

import serial
import binascii

class SYM1(serial.Serial):
    def __init__(self, *args, debug=None, baudrate=4800, timeout=1, **kwargs):
        super().__init__(*args, baudrate=baudrate, timeout=timeout, **kwargs)
        print('using port', self.port)

    def read(self, count):
        print('reading',count)
        retval = super().read(count)
        print(binascii.hexlify(bytearray(retval)))
        return retval;

    def write(self, data):

        print('writing',len(data))

        print(binascii.hexlify(bytearray(data)))

        return super().write(data)

    def connect(self):
        return super().connect()

and inside usb_backend_process.py line 52 replaced:

port = serial.Serial(port=port_name.device, timeout=None)

with

port = snifferSerial.SYM1(port=port_name.device, timeout=None)

Then it simply shows raw bytes on each command on the console. Anyways thanks for the great work!

epsi1on commented 1 month ago

i think you didn't pushed the commit yet. :) could you please push? would be thankful :) Thanks again...

FilipDominec commented 1 month ago

You are right, I will push it ASAP but I am not at the right computer. But the sufficient fix is posted above.

Thanks again.

epsi1on commented 1 month ago

yes, i actually did update the code and with new code it look extremely fine! Thank you