embassy-rs / embassy

Modern embedded framework, using Rust and async.
https://embassy.dev
Apache License 2.0
5.22k stars 718 forks source link

[RPI Pico W] Measuring vsys voltage #3273

Open eldiGH opened 3 weeks ago

eldiGH commented 3 weeks ago

I'm trying to measure the VSYS voltage using built-in ADC (to monitor battery level). It's much harder to do that compared to normal pico, as ADC connected to vsys uses pin 29, which is also used as pio spi to communicate with cyw43 wifi chip. Normally, in c/c++ sdk code would look something like this:

  adc_init();

  // Stopping background communication to cyw chip on other thread 
  cyw43_thread_enter();

  // Setting pin 29 gpio function to GPIO_FUNC_NULL instead of GPIO_FUNC_PIO1 and disables pulls along with digital receivers 
  adc_gpio_init(PICO_VSYS_PIN);

  // Selecting channel 3 of adc, which is VSYS voltage
  adc_select_input(3);

  (...standard adc read code)

  // Restoring previous pin function
  gpio_set_function(PICO_VSYS_PIN, GPIO_FUNC_PIO1);

  // Setting default pullup
  gpio_pull_up(PICO_VSYS_PIN);

  // Resuming cyw43 chip communication
  cyw43_thread_exit();

I can't really think of any way doing it safely in current embassy-rp implementation myself - maybe there is some elegant way of implementing this. I'm now developing my first project in it as well as in rust in general.

Dirbaio commented 3 weeks ago

oof, what. they shared the ADC pin with the cyw43 spi :sob:

The least bad way to add support for this would be to somehow extend cyw43-pio so it can do the pin sharing somewhat safely.

1-rafael-1 commented 3 weeks ago

I had the same issue, spent way too much time on it and then decided to hack it in hardware. Wire from vsys through a voltage divider and wire back from there to one of the adc capable pins... measure that. Really not an elegant solution but quickly done, cheap and works well.