Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ App|Description
[adc_console](adc/adc_console)|An interactive shell for playing with the ADC. Includes example of free-running capture mode.
[onboard_temperature](adc/onboard_temperature)|Display the value of the onboard temperature sensor.
[microphone_adc](adc/microphone_adc)|Read analog values from a microphone and plot the measured sound amplitude.
[read_vsys](adc/read_vsys)|Demonstrates how to read VSYS to get the voltage of the power supply.

### Clocks

Expand Down
1 change: 1 addition & 0 deletions adc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ if (NOT PICO_NO_HARDWARE)
add_subdirectory(joystick_display)
add_subdirectory(onboard_temperature)
add_subdirectory(microphone_adc)
add_subdirectory(read_vsys)
endif ()
30 changes: 30 additions & 0 deletions adc/read_vsys/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
add_library(power_status_adc INTERFACE)
target_sources(power_status_adc INTERFACE
${CMAKE_CURRENT_LIST_DIR}/power_status.c
)
target_include_directories(power_status_adc INTERFACE
${CMAKE_CURRENT_LIST_DIR}
)
target_link_libraries(power_status_adc INTERFACE
hardware_adc
hardware_gpio
)

add_executable(read_vsys
read_vsys.c
)
target_include_directories(read_vsys PRIVATE
${CMAKE_CURRENT_LIST_DIR}
)
target_link_libraries(read_vsys
pico_stdlib
power_status_adc
)
if (PICO_CYW43_SUPPORTED)
target_link_libraries(read_vsys
pico_cyw43_arch_none
)
endif()

pico_add_extra_outputs(read_vsys)
example_auto_set_url(read_vsys)
78 changes: 78 additions & 0 deletions adc/read_vsys/power_status.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/**
* Copyright (c) 2023 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/

#include "stdbool.h"
#include "hardware/adc.h"
#include "power_status.h"

#if CYW43_USES_VSYS_PIN
#include "pico/cyw43_arch.h"
#endif

#ifndef PICO_POWER_SAMPLE_COUNT
#define PICO_POWER_SAMPLE_COUNT 3
#endif

// Pin used for ADC 0
#define PICO_FIRST_ADC_PIN 26

int power_source(bool *battery_powered) {
#if defined CYW43_WL_GPIO_VBUS_PIN
*battery_powered = !cyw43_arch_gpio_get(CYW43_WL_GPIO_VBUS_PIN);
return PICO_OK;
#elif defined PICO_VBUS_GPIO_PIN
gpio_set_function(PICO_VBUS_GPIO_PIN, GPIO_FUNC_SIO);
*battery_powered = !gpio_get(PICO_VBUS_GPIO_PIN);
return PICO_OK;
#else
return PICO_ERROR_NO_DATA;
#endif
}

int power_voltage(float *voltage_result) {
#ifndef PICO_VSYS_PIN
return PICO_ERROR_NO_DATA;
#endif
#if CYW43_USES_VSYS_PIN
cyw43_thread_enter();
// Make sure cyw43 is awake
cyw43_arch_gpio_get(CYW43_WL_GPIO_VBUS_PIN);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cyw43_arch_gpio_get communicates with the wifi chip, and also calls to cyw43_thread_enter and cyw43_thread_exit.

Would that not cause conflicts and or release our lock too soon?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you seeing an issue? You can nest calls to enter and exit so I wouldn't expect this to be a problem.

#endif

// setup adc
adc_gpio_init(PICO_VSYS_PIN);
adc_select_input(PICO_VSYS_PIN - PICO_FIRST_ADC_PIN);

adc_fifo_setup(true, false, 0, false, false);
adc_run(true);

#if CYW43_USES_VSYS_PIN
// We seem to read low values from cyw43 sometimes - this seems to fix it
int ignore_count = PICO_POWER_SAMPLE_COUNT;
while (!adc_fifo_is_empty() || ignore_count-- > 0) {
(void)adc_fifo_get_blocking();
}
#endif

// read vsys
uint32_t vsys = 0;
for(int i = 0; i < PICO_POWER_SAMPLE_COUNT; i++) {
uint16_t val = adc_fifo_get_blocking();
vsys += val;
}

adc_run(false);
adc_fifo_drain();

vsys /= PICO_POWER_SAMPLE_COUNT;
#if CYW43_USES_VSYS_PIN
cyw43_thread_exit();
#endif
// Generate voltage
const float conversion_factor = 3.3f / (1 << 12);
*voltage_result = vsys * 3 * conversion_factor;
return PICO_OK;
}
33 changes: 33 additions & 0 deletions adc/read_vsys/power_status.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/**
* Copyright (c) 2023 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/

#ifndef POWER_STATUS_H
#define POWER_STATUS_H

/*!
* \brief Get power source
*
* Returns whether battery powered
* \note On Pico W must have called cyw43_arch_init
*
* \param battery_powered True if powered by battery, False if powered by USB or another means
* \return Zero if the battery status can be determined, an error code otherwise \see pico_error_codes
*/

int power_source(bool *battery_powered);

/*!
* \brief Get system voltage
*
* Returns the system voltage
* \note Must have called adc_init
*
* \param voltage Calculated voltage
* \return Zero if the voltage can be determined, an error code otherwise \see pico_error_codes
*/
int power_voltage(float *voltage);

#endif
75 changes: 75 additions & 0 deletions adc/read_vsys/read_vsys.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/**
* Copyright (c) 2022 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/

#include <stdio.h>
#include <pico/stdlib.h>
#include <power_status.h>
#include "hardware/adc.h"
#include "pico/float.h"

#if CYW43_USES_VSYS_PIN
#include "pico/cyw43_arch.h"
#endif

int main() {
stdio_init_all();

adc_init();
adc_set_temp_sensor_enabled(true);

// Pico W uses a CYW43 pin to get VBUS so we need to initialise it
#if CYW43_USES_VSYS_PIN
if (cyw43_arch_init()) {
printf("failed to initialise\n");
return 1;
}
#endif

bool old_battery_status;
float old_voltage;
bool battery_status = true;
char *power_str = "UNKNOWN";

while(true) {
// Get battery status
if (power_source(&battery_status) == PICO_OK) {
power_str = battery_status ? "BATTERY" : "POWERED";
}

// Get voltage
float voltage = 0;
int voltage_return = power_voltage(&voltage);
voltage = floorf(voltage * 100) / 100;

// Display power if it's changed
if (old_battery_status != battery_status || old_voltage != voltage) {
char percent_buf[10] = {0};
if (battery_status && voltage_return == PICO_OK) {
const float min_battery_volts = 3.0f;
const float max_battery_volts = 4.2f;
int percent_val = ((voltage - min_battery_volts) / (max_battery_volts - min_battery_volts)) * 100;
snprintf(percent_buf, sizeof(percent_buf), " (%d%%)", percent_val);
}

// Also get the temperature
adc_select_input(4);
const float conversionFactor = 3.3f / (1 << 12);
float adc = (float)adc_read() * conversionFactor;
float tempC = 27.0f - (adc - 0.706f) / 0.001721f;

// Display power and remember old vales
printf("Power %s, %.2fV%s, temp %.1f DegC\n", power_str, voltage, percent_buf, tempC);
old_battery_status = battery_status;
old_voltage = voltage;
}
sleep_ms(1000);
}

#if CYW43_USES_VSYS_PIN
cyw43_arch_deinit();
#endif
return 0;
}