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

Unable to measure VSYS/ADC3/GPIO29 with WIFI #1222

Closed
pspeybro opened this issue Feb 5, 2023 · 22 comments
Closed

Unable to measure VSYS/ADC3/GPIO29 with WIFI #1222

pspeybro opened this issue Feb 5, 2023 · 22 comments
Assignees

Comments

@pspeybro
Copy link

pspeybro commented Feb 5, 2023

I have a setup with Pico W + pimoroni lipo shim.
I am trying to run it on batteries, measure some sensors and submit the data via wifi.
I am also trying to check battery status from time to time to get an idea when charging is needed. There is a micropython example here, but I found that this also does not work for Pico W.

I also looked on this forum thread where others also struggle with doing this with python in combination with using WIFI.
https://forums.raspberrypi.com/viewtopic.php?p=2078340#p2078340 (my username = Darkness)

I am trying to accomplish this using the SDK.

From the datasheet:
`GPIO29 OP/IP wireless SPI CLK/ADC mode (ADC3) to measure VSYS/3
GPIO25 OP wireless SPI CS - when high also enables GPIO29 ADC pin to read VSYS
WL_GPIO2 IP VBUS sense - high if VBUS is present, else low

Due to pin limitations, some of the wireless interface pins are shared. The CLK is shared with VSYS monitor, so only
when there isn’t an SPI transaction in progress can VSYS be read via the ADC. The Infineon CYW43439 DIN/DOUT and
IRQ all share one pin on the RP2040. Only when an SPI transaction isn’t in progress is it suitable to check for IRQs. The
interface typically runs at 33MHz`

So it is clear that due to pins being shared with the wifi chip, it is not possible to measure VSYS using GPIO29+GPIO25.

  • is there a way to know if an SPI transaction is in progress or not to make sure an ADC3 measurement can be done?
  • Is there a reliable way to repeatedly enable and disable wifi to make GPIO29 and GPIO25 available? I tryied calling cyw43_arch_deinit() but afterwards cyw43_arch_init() seems to fail and hang the pico.
  • is cyw43_arch_gpio_get(2); the correct way to read WL_GPIO2/VBUS sense? pico_w.h does not contain a definition for these pins, unlike the #define CYW43_WL_GPIO_LED_PIN 0

This seems like a very common use case, so an example would be very useful for the community.

@kilograham
Copy link
Contributor

cc @dp111

@peterharperuk
Copy link
Contributor

peterharperuk commented Feb 6, 2023

is there a way to know if an SPI transaction is in progress or not to make sure an ADC3 measurement can be done?
Is there a reliable way to repeatedly enable and disable wifi to make GPIO29 and GPIO25 available?

Hi. If you're writing C code using pico-sdk, you shouldn't really need to know when a SPI transaction is in progress or disable WIFI. We set the chip select low when we're using SPI to talk to the wifi chip and then set it high again when we're done. If you want to read VSYS then you just need to make sure we don't do any wifi stuff while you're using GPIO29_ADC. You should be able to do this by wrapping your use of GPIO29_ADC with the CYW43_THREAD_ENTER / EXIT macros?

I'm not sure this helps a lot with Micropython - I'll have to think about that, and read the forum thread.

is cyw43_arch_gpio_get(2); the correct way to read WL_GPIO2/VBUS sense?

I can add a #define for the gpio if it helps. (later: edited, you're fine to call this inside CYW43_THREAD_ENTER / EXIT)

This seems like a very common use case, so an example would be very useful for the community

Yes, good point raspberrypi/pico-examples#324

@peterharperuk
Copy link
Contributor

Maybe we should support a rp2.read_vsys method in Micropython?

@pspeybro
Copy link
Author

pspeybro commented Feb 6, 2023

I'm just using C or C++, not micropython. It's just the pimoroni example and forum thread that are using micropython.

I will try with the CYW43_THREAD_ENTER / EXIT. I did not encounter these before. Are they explained somewhere in the datasheet or documentation?

Also, do I need to pull GPIO25 high to read GPIO29_ADC?

An extra #define is not strictly necesary, but because the datasheet refers to WL_GPIO2 and micropython seems to define that, it might be useful if those WL_GPIO1 and WL_GPIO2 are also defined, so that you do not need to guess that these just correspond to 1 and 2.

I was considering making an issue in the example repo, so thank you for doing that. If I get my test working, I will post the code there.

@peterharperuk
Copy link
Contributor

Also, do I need to pull GPIO25 high to read GPIO29_ADC?

I haven't tested it yet but it has to be high (famous last words) while we're not doing anything with wifi or else a spi transaction would be ongoing? You might have to change the function of gpio 29 while you're reading from it and restore it before calling
CYW43_THREAD_EXIT.

I did not encounter these before. Are they explained somewhere in the datasheet or documentation?

There's some discussion in the examples of using this for for networking w.r.t. cyw43_arch_lwip_begin. In the latest sdk (soon to be released) there's a new asynchronous api that has an explicit lock function which might be more obvious.

Out of interest, what "method" are you using to build your code? I'm guessing you're linking to pico_cyw43_arch_lwip_threadsafe_background? If you use "poll" you shouldn't even need the lock.

@pspeybro
Copy link
Author

pspeybro commented Feb 6, 2023

Out of interest, what "method" are you using to build your code? I'm guessing you're linking to pico_cyw43_arch_lwip_threadsafe_background? If you use "poll" you shouldn't even need the lock.

Indeed, I am using pico_cyw43_arch_lwip_threadsafe_background, as I was under the impression that polling is generally less efficient, but I did not read up on that in detail yet...

@kilograham
Copy link
Contributor

cyw43_thread_enter() and cyw43_thread_exit() are nominally better (but equivalent to CYW43_THREAD_ENTER and CYW43_THREAD_EXIT

still seems that neither are particularly documented.

@pspeybro
Copy link
Author

pspeybro commented Feb 6, 2023

That cyw43_thread_enter()/cyw43_thread_exit() definitely seems to improve things. (requires #include "pico/cyw43_arch/arch_threadsafe_background.h")

Checking VBUS/WL_GPIO2 seems to correctly indicate whether powered from usb or battery.

Initializing the ADC3 between the enter/exit seems to work as well and no need to set GPIO25 high.

Below is the log from the data submitted via wifi to my api. Capacitive moisture sensor on ADC2, 1-wire temperature sensor, VSYS and VBUS

[2023-37-06 22:37:41] Moisture: 2,491, Temperature: 20,5, Voltage: 4,981, Vbus: 1 <- USB
[2023-37-06 22:37:43] Moisture: 2,486, Temperature: 20,5, Voltage: 4,984, Vbus: 1 <- USB
[2023-37-06 22:37:45] Moisture: 2,49, Temperature: 20,5, Voltage: 4,123, Vbus: 0 <- Battery
[2023-37-06 22:37:46] Moisture: 2,49, Temperature: 20,5, Voltage: 4,123, Vbus: 0 <- Battery
[2023-37-06 22:37:48] Moisture: 2,49, Temperature: 20,5, Voltage: 4,126, Vbus: 0 <- Battery
[2023-37-06 22:37:50] Moisture: 2,49, Temperature: 20,5, Voltage: 4,984, Vbus: 1 <- USB
[2023-37-06 22:37:52] Moisture: 2,489, Temperature: 20,5, Voltage: 4,979, Vbus: 1 <- USB

Vbus is nicely going to 0 when unplugging usb, and the voltage (VSYS/GPIO29_ADC ) measurement goes from 4.98 to 4.12 when switching to battery. This way I can skip reading the VSYS when connected via USB.

We do need to restore the GPIO29_ADC setting back to the wifi settings. After checking the pin settings during wifi and ADC, it seems I need to set the function back to USB and pull down (though the pull down did not seem necessary)
gpio_set_function(29, GPIO_FUNC_PIO1); //7
gpio_pull_down(29); //does not seem necessary, but this way it is back to how it was before adc_gpio_init(29);

I will clean up my code a little bit and post it in the example issue

Thank you very much for the hints!

@pspeybro
Copy link
Author

pspeybro commented Feb 6, 2023

Pull request with example code: raspberrypi/pico-examples#326

@liaan
Copy link

liaan commented Feb 7, 2023

Hi, Apologies first, I have no knowledge of micropython. But was wondering, can one not have a interrupt Lising on the CS going high (wifi not communicating), Set pin 29 to analogue, read, revert, and then continue?

Not sure how interrupt priorities work with micropython, might be a option?

@peterharperuk
Copy link
Contributor

It's the same on MP except you have to use pendsv_suspend / pendsv_resume instead of cyw43_thread_enter / cyw43_thread_exit. Thus my suggestion that we add a rp2 method to read vsys as reading the gpio from MP won't take the lock. I don't much fancy exposing the lock in MP.

peterharperuk added a commit to peterharperuk/pico-sdk that referenced this issue Feb 10, 2023
The process for reading VBUS and VSYS on Pico and Pico W is different.
It's hard to write code that compiles for both devices.
Add some configuration to the board files.

Fixes raspberrypi#1222
@peterharperuk
Copy link
Contributor

See my attempt raspberrypi/pico-examples#331

peterharperuk added a commit to peterharperuk/pico-sdk that referenced this issue Feb 14, 2023
The process for reading VBUS and VSYS on Pico and Pico W is different.
It's hard to write code that compiles for both devices.
Add some configuration to the board files.

Fixes raspberrypi#1222
peterharperuk added a commit to peterharperuk/pico-sdk that referenced this issue Feb 14, 2023
The process for reading VBUS and VSYS on Pico and Pico W is different.
It's hard to write code that compiles for both devices.
Add some configuration to the board files.

Fixes raspberrypi#1222
@ZodiusInfuser
Copy link
Contributor

Hi All, I just want to chime in here with my support for a proper way to read the vsys voltage on Pico W from Micropython.

At Pimoroni we have the Enviro range of products which have a Pico W Aboard, and we had hoped to use the onboard VSYS measurement to measure the board's battery voltage. And indeed we can do this, but not without causing issues with the WiFi communication down the line. We tried doing the reading when the CS pin was not selected, without success, and currently have a customer PR that reportedly works pimoroni/enviro#146 but I would like much more testing done before merging it in and having it enabled by default.

@peterharperuk
Copy link
Contributor

a proper way to read the vsys voltage on Pico W from Micropython

The Micropython repo is here https://github.com/micropython/micropython

@ZodiusInfuser
Copy link
Contributor

Yes, I am very much aware. You said yourself though that:

Maybe we should support a rp2.read_vsys method in Micropython?

I was showing my support for that.

@pspeybro
Copy link
Author

pspeybro commented Mar 5, 2023

Just a followup to this issue. In my tests with wifi, getting the VSYS value is working nicely without a problem.
However, with the new release of the SDK 1.5.0, I thought of trying this while using bluetooth LE instead of wifi and now I seem to get very low values again (almost zero).

I already tried a few things like the cyw43_thread_enter()/cyw43_thread_exit() even though I am using pico_cyw43_arch_none.

Link libraries (cmake):
pico_stdlib
hardware_adc # for ADC
pico_btstack_ble
pico_btstack_cyw43
pico_cyw43_arch_none

Also recompiling my previously working code with wifi using SDK 1.5 is still working.
Is there something regarding bluetooth that might prevent getting the VSYS/ADC3 voltage?

Getting the VBUS value (to check if it is charging or on battery is working.

@peterharperuk
Copy link
Contributor

Is there something regarding bluetooth that might prevent getting the VSYS/ADC3 voltage?

I can't think of anything. Are you sure you've accounted for the differences between Pico and Pico W? I can check with my example when I have time raspberrypi/pico-examples#331

tried a few things like the cyw43_thread_enter()/cyw43_thread_exit() even though I am using pico_cyw43_arch_none.

pico_cyw43_arch_none is "threadsafe background" without lwip. You absolutely have to call cyw43_thread_enter()/cyw43_thread_exit if you want to measure vsys on Pico W.

@pspeybro
Copy link
Author

pspeybro commented Mar 6, 2023

I continued from my working example, but I will compare with your example again.
Thank you for confirming the need to call cyw43_thread_enter()/cyw43_thread_exit.

I will also check the before and after settings of the gpio to see if I need to restore it to different settings compared to wifi, but also the initial reading is not showing the correct value, so that does not seem to be the cause.

@pspeybro
Copy link
Author

pspeybro commented Mar 7, 2023

After stripping my wifi code and adding the bluetooth parts, it seems to be working now. I still need to compare it with my previous version to see what's different but it seems stable now.

I did have some issues where the voltage measured seemed unstable, starting at 5.02 and then dropping towards 3.5 after 15-20 seconds, even though it was connected with usb. Not sure what caused that, but might have been before I added hci_power_control(HCI_POWER_ON);

@peterharperuk
Copy link
Contributor

I think I see the same behaviour with some instability (I improved this by reading multiple times) and high values on the first read. I'll see if the hw engineer has any thought on why this might be the case.

@dp111
Copy link
Contributor

dp111 commented Mar 9, 2023 via email

kilograham pushed a commit that referenced this issue Mar 27, 2023
The process for reading VBUS and VSYS on Pico and Pico W is different.
It's hard to write code that compiles for both devices.
Add some configuration to the board files.

Fixes #1222
@kilograham
Copy link
Contributor

closing as this seems to be resolved

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

6 participants