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

basic example code for Issue/324 on reading VSYS/VBUS while using wifi on Pico_W #326

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ App|Description

### Pico W Networking

These eaxmples are for the Pico W, and are only available for `PICO_BOARD=pico_w`
These examples are for the Pico W, and are only available for `PICO_BOARD=pico_w`

App|Description
---|---
Expand Down
53 changes: 53 additions & 0 deletions pico_w/wifi_vsys/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Generated Cmake Pico project file

cmake_minimum_required(VERSION 3.13)

set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)

# Initialise pico_sdk from installed location
# (note this can come from environment, CMake cache etc)
set(PICO_SDK_PATH "/home/username/pico/pico-sdk")
set(PICO_EXTRAS_PATH "/home/username/pico/pico-extras")

set(PICO_BOARD pico_w CACHE STRING "Board type")

# Pull in Raspberry Pi Pico SDK (must be before project)
include(pico_sdk_import.cmake)
include(${PICO_EXTRAS_PATH}/external/pico_extras_import.cmake)


if (PICO_SDK_VERSION_STRING VERSION_LESS "1.4.0")
message(FATAL_ERROR "Raspberry Pi Pico SDK version 1.4.0 (or later) required. Your version is ${PICO_SDK_VERSION_STRING}")
endif()

project(wifi_vsys C CXX ASM)

# Initialise the Raspberry Pi Pico SDK
pico_sdk_init()

# Add executable. Default name is the project name, version 0.1

add_executable(wifi_vsys wifi_vsys.cpp )

pico_set_program_name(wifi_vsys "wifi_vsys")
pico_set_program_version(wifi_vsys "0.1")

pico_enable_stdio_uart(wifi_vsys 0)
pico_enable_stdio_usb(wifi_vsys 1)

# Add the standard library to the build
target_link_libraries(wifi_vsys
pico_stdlib
pico_lwip_http
pico_cyw43_arch_lwip_threadsafe_background
hardware_adc
)

# Add the standard include files to the build
target_include_directories(wifi_vsys PRIVATE
${CMAKE_CURRENT_LIST_DIR}
${CMAKE_CURRENT_LIST_DIR}/.. # for our common lwipopts or any other standard includes, if required
)

pico_add_extra_outputs(wifi_vsys)
10 changes: 10 additions & 0 deletions pico_w/wifi_vsys/lwipopts.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#ifndef _LWIPOPTS_H
#define _LWIPOPTS_H

// Generally you would define your own explicit list of lwIP options
// (see https://www.nongnu.org/lwip/2_1_x/group__lwip__opts.html)
//
// This example uses a common include to avoid repetition
#include "lwipopts_examples_common.h"

#endif
158 changes: 158 additions & 0 deletions pico_w/wifi_vsys/wifi_vsys.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
#include <stdio.h>
#include "pico/stdlib.h"
#include "pico/cyw43_arch.h"
#include "hardware/gpio.h"
#include "hardware/adc.h" //to read ADC for soil moisture sensor, connected to pin 36 (3.3V), pin 33 (GND/AGND), pin 34 (GPIO28/ADC2)
Copy link
Contributor

Choose a reason for hiding this comment

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

soil moisture sensor - huh?

Copy link
Author

Choose a reason for hiding this comment

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

one of these: https://arduino-tutorials.net/tutorial/capacitive-soil-moisture-sensor-arduino
I left the sensor reading in there to make the example at least a little more interesting.

#include "lwip/apps/http_client.h" //http client
#include "pico/cyw43_arch/arch_threadsafe_background.h" //to get access to void cyw43_thread_enter(void); and void cyw43_thread_exit(void);

#ifndef CYW43_WL_GPIO2
#define CYW43_WL_GPIO2 2 //this is not defined in pico_w.h
#endif

const float conversion_factor = 3.3f / (1 << 12); //ADC_VREF=3.3, so this is the ADC resolution.
const char ssid[] = "myWifiNetwork";
const char pass[] = "myWifiPassword";
const uint32_t auth = CYW43_AUTH_WPA2_MIXED_PSK;

//Http client variables
bool httpBusy = false;
char httpBuff[1000]; //if not big enough to read the result or headers, pico will hang.
httpc_connection_t settings;
ip_addr_t ip;
char apicall[64];


//handler for HTTP client result
void httpresult(void *arg, httpc_result_t httpc_result, u32_t rx_content_len, u32_t srv_res, err_t err){
printf("[1] local result=%d http result=%d\n", httpc_result, srv_res);
}

//handler for HTTP client headers
err_t headers(httpc_state_t *connection, void *arg, struct pbuf *hdr, u16_t hdr_len, u32_t content_len){
pbuf_copy_partial(hdr, httpBuff, hdr->tot_len, 0);
printf("[1] content length=%d, header length %d, headers: %s\n", content_len, hdr_len, httpBuff);
//free memory
pbuf_free(hdr);
return ERR_OK;
}

//handler for HTTP client body
err_t body(void *arg, struct altcp_pcb *conn, struct pbuf *p, err_t err){
pbuf_copy_partial(p, httpBuff, p->tot_len, 0);
printf("[1] body: %s", httpBuff);
httpBusy = false;
//free memory
pbuf_free(p);
return ERR_OK;
}

//Set GPIO29 back to settings for wifi usage (shared pin with ADC3, so settings are changed when activating ADC3)
void SetGPIO29WifiStatus(){
gpio_set_function(29, GPIO_FUNC_PIO1); //7
gpio_pull_down(29);
gpio_set_slew_rate(29, GPIO_SLEW_RATE_FAST); //1
gpio_set_drive_strength(29, GPIO_DRIVE_STRENGTH_12MA); //3
}

int main() {
stdio_init_all();
adc_init();
adc_gpio_init(28);

//Initialize wifi
if (cyw43_arch_init()) {
printf("WiFi init failed.\n");
return 1;
}
cyw43_arch_enable_sta_mode();
//connect to access point
if (cyw43_arch_wifi_connect_timeout_ms(ssid, pass, auth, 30000)) {
printf("failed to connect.\n");
return 1;
} else {
printf("Connected.\n");
}

//set http client handlers
settings.result_fn = httpresult;
settings.headers_done_fn = headers;
//define IP address that hosts the web api to send the data
IP4_ADDR(&ip, 192, 168, 0, 1);
int ledStatus = 0;
float vsys=0;

while(true) {
//flip onboard led
ledStatus = 1 - ledStatus;
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, ledStatus);

//Select ADC2 to read moisture sensor
adc_select_input(2);
uint16_t result = adc_read();
float voltage = result * conversion_factor;
printf("ADC2 value: 0x%03x, %i, voltage: %3.1f V\n", result, result, voltage);

//make sure there is not HTTP request in progress or other wifi activity when we want to check the battery status
if (!httpBusy){
httpBusy = true;

//prevent wifi background processing so we can use the shared pins
cyw43_thread_enter(); //or macro: CYW43_THREAD_ENTER

//WL_GPIO2, IP VBUS sense - high if VBUS is present, else low
uint vbus = cyw43_arch_gpio_get(CYW43_WL_GPIO2);

//we could decide to only check the voltage if not powered by USB port/VBUS and perhaps not check it every cycle.
//if (vbus==0) {

//initialize and select ADC3/GPIO29
adc_gpio_init(29);
adc_select_input(3);

//Read ADC3, result is 1/3 of VSYS, so we still need to multiply the conversion factor with 3 to get the input voltage
uint16_t adc3 = adc_read();
vsys = adc3 * conversion_factor * 3;
printf("ADC3 value: 0x%03x, %i, voltage: %f V\n", adc3, adc3, vsys);
//set GPIO29 back to the settings for wifi, otherwise cyw43 will not work correctly
SetGPIO29WifiStatus();
//}
//else{
//USB/VSYS powered, do nothing (voltage should be somewhere around 5V)
//}
//exit to allow wifi communication again
cyw43_thread_exit(); //or macro: CYW43_THREAD_EXIT

sprintf(apicall, "/api/echo?m=%3.3f&v=%3.3f&b=%i", voltage, vsys, vbus);
printf("Calling API: %s\n", apicall);
err_t err = httpc_get_file(
&ip, //IP address hosting the API
5131, //port
apicall, //api call
&settings, //handlers for result/headers
body, //handler for body
NULL,
NULL
);
printf("[1] http status %d \n", err);
}
else{
printf("[1] http client is busy...\n");
Comment on lines +137 to +140
Copy link
Contributor

Choose a reason for hiding this comment

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

What are all these [1] supposed to indicate?

Copy link
Author

Choose a reason for hiding this comment

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

ah, some leftover from debugging, totally irrelevant

Copy link
Author

Choose a reason for hiding this comment

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

leftover, as in, I was running the http request on core1 initially, so it was indicating from which core the printf was coming...

}

#if PICO_CYW43_ARCH_POLL
// if you are using pico_cyw43_arch_poll, then you must poll periodically from your
// main loop (not from a timer) to check for WiFi driver or lwIP work that needs to be done.
cyw43_arch_poll();
sleep_ms(1);
#else
// if you are not using pico_cyw43_arch_poll, then WiFI driver and lwIP work
// is done via interrupt in the background. This sleep is just an example of some (blocking)
// work you might be doing.
sleep_ms(5000);
#endif
}

cyw43_arch_deinit();
return 0;
}
74 changes: 37 additions & 37 deletions pio/ws2812/ws2812_parallel.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@
#define WS2812_PIN_BASE 2

// horrible temporary hack to avoid changing pattern code
static uint8_t *current_string_out;
static bool current_string_4color;
static uint8_t *current_strip_out;
static bool current_strip_4color;

static inline void put_pixel(uint32_t pixel_grb) {
*current_string_out++ = pixel_grb & 0xffu;
*current_string_out++ = (pixel_grb >> 8u) & 0xffu;
*current_string_out++ = (pixel_grb >> 16u) & 0xffu;
if (current_string_4color) {
*current_string_out++ = 0; // todo adjust?
*current_strip_out++ = pixel_grb & 0xffu;
*current_strip_out++ = (pixel_grb >> 8u) & 0xffu;
*current_strip_out++ = (pixel_grb >> 16u) & 0xffu;
if (current_strip_4color) {
*current_strip_out++ = 0; // todo adjust?
}
}

Expand Down Expand Up @@ -83,9 +83,9 @@ void pattern_solid(uint len, uint t) {
}
}

int level = 8;

void pattern_fade(uint len, uint t) {
const int level = 8;
uint shift = 4;

uint max = 16; // let's not draw too much current!
Expand All @@ -95,7 +95,7 @@ void pattern_fade(uint len, uint t) {
slow_t = level;
slow_t %= max;

static int error;
static int error = 0;
slow_t += error;
error = slow_t & ((1u << shift) - 1);
slow_t >>= shift;
Expand All @@ -121,7 +121,7 @@ const struct {

#define VALUE_PLANE_COUNT (8 + FRAC_BITS)
// we store value (8 bits + fractional bits of a single color (R/G/B/W) value) for multiple
// strings, in bit planes. bit plane N has the Nth bit of each string.
// strips of pixels, in bit planes. bit plane N has the Nth bit of each strip of pixels.
typedef struct {
// stored MSB first
uint32_t planes[VALUE_PLANE_COUNT];
Expand Down Expand Up @@ -149,17 +149,17 @@ typedef struct {
uint8_t *data;
uint data_len;
uint frac_brightness; // 256 = *1.0;
} string_t;
} strip_t;

// takes 8 bit color values, multiply by brightness and store in bit planes
void transform_strings(string_t **strings, uint num_strings, value_bits_t *values, uint value_length,
void transform_strips(strip_t **strips, uint num_strips, value_bits_t *values, uint value_length,
uint frac_brightness) {
for (uint v = 0; v < value_length; v++) {
memset(&values[v], 0, sizeof(values[v]));
for (int i = 0; i < num_strings; i++) {
if (v < strings[i]->data_len) {
for (int i = 0; i < num_strips; i++) {
if (v < strips[i]->data_len) {
// todo clamp?
uint32_t value = (strings[i]->data[v] * strings[i]->frac_brightness) >> 8u;
uint32_t value = (strips[i]->data[v] * strips[i]->frac_brightness) >> 8u;
value = (value * frac_brightness) >> 8u;
for (int j = 0; j < VALUE_PLANE_COUNT && value; j++, value >>= 1u) {
if (value & 1u) values[v].planes[VALUE_PLANE_COUNT - 1 - j] |= 1u << i;
Expand All @@ -177,29 +177,29 @@ void dither_values(const value_bits_t *colors, value_bits_t *state, const value_

// requested colors * 4 to allow for RGBW
static value_bits_t colors[NUM_PIXELS * 4];
// double buffer the state of the string, since we update next version in parallel with DMAing out old version
// double buffer the state of the pixel strip, since we update next version in parallel with DMAing out old version
static value_bits_t states[2][NUM_PIXELS * 4];

// example - string 0 is RGB only
static uint8_t string0_data[NUM_PIXELS * 3];
// example - string 1 is RGBW
static uint8_t string1_data[NUM_PIXELS * 4];
// example - strip 0 is RGB only
static uint8_t strip0_data[NUM_PIXELS * 3];
// example - strip 1 is RGBW
static uint8_t strip1_data[NUM_PIXELS * 4];

string_t string0 = {
.data = string0_data,
.data_len = sizeof(string0_data),
strip_t strip0 = {
.data = strip0_data,
.data_len = sizeof(strip0_data),
.frac_brightness = 0x40,
};

string_t string1 = {
.data = string1_data,
.data_len = sizeof(string1_data),
strip_t strip1 = {
.data = strip1_data,
.data_len = sizeof(strip1_data),
.frac_brightness = 0x100,
};

string_t *strings[] = {
&string0,
&string1,
strip_t *strips[] = {
&strip0,
&strip1,
};

// bit plane content dma channel
Expand Down Expand Up @@ -266,7 +266,7 @@ void dma_init(PIO pio, uint sm) {
irq_set_enabled(DMA_IRQ_0, true);
}

void output_strings_dma(value_bits_t *bits, uint value_length) {
void output_strips_dma(value_bits_t *bits, uint value_length) {
for (uint i = 0; i < value_length; i++) {
fragment_start[i] = (uintptr_t) bits[i].planes; // MSB first
}
Expand All @@ -285,7 +285,7 @@ int main() {
int sm = 0;
uint offset = pio_add_program(pio, &ws2812_parallel_program);

ws2812_parallel_program_init(pio, sm, offset, WS2812_PIN_BASE, count_of(strings), 800000);
ws2812_parallel_program_init(pio, sm, offset, WS2812_PIN_BASE, count_of(strips), 800000);

sem_init(&reset_delay_complete_sem, 1, 1); // initially posted so we don't block first time
dma_init(pio, sm);
Expand All @@ -299,17 +299,17 @@ int main() {
int brightness = 0;
uint current = 0;
for (int i = 0; i < 1000; ++i) {
current_string_out = string0.data;
current_string_4color = false;
current_strip_out = strip0.data;
current_strip_4color = false;
pattern_table[pat].pat(NUM_PIXELS, t);
current_string_out = string1.data;
current_string_4color = true;
current_strip_out = strip1.data;
current_strip_4color = true;
pattern_table[pat].pat(NUM_PIXELS, t);

transform_strings(strings, count_of(strings), colors, NUM_PIXELS * 4, brightness);
transform_strips(strips, count_of(strips), colors, NUM_PIXELS * 4, brightness);
dither_values(colors, states[current], states[current ^ 1], NUM_PIXELS * 4);
sem_acquire_blocking(&reset_delay_complete_sem);
output_strings_dma(states[current], NUM_PIXELS * 4);
output_strips_dma(states[current], NUM_PIXELS * 4);

current ^= 1;
t += dir;
Expand Down