samples: boards: firmware for Twinkie V2

sample firmware for Twinkie V2 that toggles the LED based on charging
status.

Signed-off-by: Jason Yuan <jasonyuan@google.com>
This commit is contained in:
Jason Yuan 2023-03-07 14:06:33 -08:00 committed by Carles Cufí
commit ad555d08d8
7 changed files with 246 additions and 0 deletions

View file

@ -0,0 +1,9 @@
# SPDX-License-Identifier: Apache-2.0
cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(google_twinkie_v2)
FILE(GLOB app_sources src/*.c)
target_sources(app PRIVATE ${app_sources})

View file

@ -0,0 +1,25 @@
.. _google_twinkie_v2_pda:
Twinkie Power Delivery
######################
Overview
********
This provides access to :ref:`Twinkie <google_twinkie_v2_board>` so you can try out
the supported features.
Building and Running
********************
Build and flash Twinkie as follows:
.. zephyr-app-commands::
:zephyr-app: samples/boards/google_pda
:board: google_twinkie_v2
:goals: build flash
:compact:
After flashing, the LED will start red. Putting the Twinkie in between any
usbc connection will cause the LED to turn blue. The LED will turn green instead
if the device is currently charging.

View file

@ -0,0 +1,4 @@
CONFIG_ADC=y
CONFIG_ADC_STM32=y
CONFIG_GPIO=y
CONFIG_LED=y

View file

@ -0,0 +1,6 @@
sample:
name: Twinkie V2 usb Vbus snooper
tests:
sample.board.google_twinkie_v2:
platform_allow: google_twinkie_v2
tags: usb

View file

@ -0,0 +1,102 @@
/*
* Copyright (c) 2023 The ChromiumOS Authors
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <zephyr/kernel.h>
#include <zephyr/drivers/adc.h>
#include <zephyr/drivers/adc/voltage_divider.h>
#include <zephyr/drivers/adc/current_sense_amplifier.h>
/* The devicetree node identifier for the adc aliases. */
#define VBUS_V_MEAS_NODE DT_ALIAS(vbus)
#define VBUS_C_MEAS_NODE DT_ALIAS(cbus)
static const struct voltage_divider_dt_spec adc_vbus_v =
VOLTAGE_DIVIDER_DT_SPEC_GET(VBUS_V_MEAS_NODE);
static const struct current_sense_amplifier_dt_spec adc_vbus_c =
CURRENT_SENSE_AMPLIFIER_DT_SPEC_GET(VBUS_C_MEAS_NODE);
int meas_vbus_v(int32_t *v)
{
int ret;
int32_t sample_buffer = 0;
/* Structure defining an ADC sampling sequence */
struct adc_sequence sequence = {
.buffer = &sample_buffer,
/* buffer size in bytes, not number of samples */
.buffer_size = sizeof(sample_buffer),
.calibrate = true,
};
adc_sequence_init_dt(&adc_vbus_v.port, &sequence);
ret = adc_read(adc_vbus_v.port.dev, &sequence);
if (ret != 0) {
return ret;
}
*v = sample_buffer;
ret = adc_raw_to_millivolts_dt(&adc_vbus_v.port, v);
if (ret != 0) {
return ret;
}
ret = voltage_divider_scale_dt(&adc_vbus_v, v);
if (ret != 0) {
return ret;
}
return 0;
}
int meas_vbus_c(int32_t *c)
{
int ret;
int32_t sample_buffer = 0;
/* Structure defining an ADC sampling sequence */
struct adc_sequence sequence = {
.buffer = &sample_buffer,
/* buffer size in bytes, not number of samples */
.buffer_size = sizeof(sample_buffer),
.calibrate = true,
};
adc_sequence_init_dt(&adc_vbus_c.port, &sequence);
ret = adc_read(adc_vbus_c.port.dev, &sequence);
if (ret != 0) {
return ret;
}
*c = sample_buffer;
ret = adc_raw_to_millivolts_dt(&adc_vbus_c.port, c);
if (ret != 0) {
return ret;
}
/* prescaling the voltage offset */
*c -= adc_vbus_c.port.vref_mv / 2;
current_sense_amplifier_scale_dt(&adc_vbus_c, c);
return 0;
}
int meas_init(void)
{
int ret;
ret = adc_channel_setup_dt(&adc_vbus_v.port);
if (ret != 0) {
return ret;
}
ret = adc_channel_setup_dt(&adc_vbus_c.port);
if (ret != 0) {
return ret;
}
return 0;
}

View file

@ -0,0 +1,36 @@
/*
* Copyright (c) 2023 The ChromiumOS Authors
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __MEAS_H__
#define __MEAS_H__
/**
* @brief Initializes the measurement module, sets up all the adc channels through the device tree
* binding
*
* @return 0 on success
*/
int meas_init(void);
/**
* @brief Measure the voltage on VBUS
*
* @param v pointer where VBUS voltage, in millivolts, is stored
*
* @return 0 on success
*/
int meas_vbus_v(int32_t *v);
/**
* @brief Measure the current on VBUS
*
* @param c pointer where VBUS current, in milliamperes, is stored
*
* @return 0 on success
*/
int meas_vbus_c(int32_t *c);
#endif

View file

@ -0,0 +1,64 @@
/*
* Copyright (c) 2023 The ChromiumOS Authors
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/device.h>
#include <zephyr/drivers/led.h>
#include <zephyr/kernel.h>
#include "meas.h"
enum led_color_t {
LED_RED,
LED_GREEN,
LED_BLUE,
};
static void set_led(const struct device *const led, enum led_color_t led_color)
{
if (led_color != LED_RED) {
led_off(led, LED_RED);
}
if (led_color != LED_GREEN) {
led_off(led, LED_GREEN);
}
if (led_color != LED_BLUE) {
led_off(led, LED_BLUE);
}
led_on(led, led_color);
}
#define CHARGING_VOLTAGE 5000
#define CHARGING_CURRENT 1000
void main(void)
{
meas_init();
const struct device *const led = DEVICE_DT_GET_ONE(gpio_leds);
int32_t vbus_v = 0;
int32_t vbus_c = 0;
if (!device_is_ready(led)) {
return;
}
while (1) {
meas_vbus_v(&vbus_v);
meas_vbus_c(&vbus_c);
if (vbus_v > CHARGING_VOLTAGE) {
if (vbus_c > CHARGING_CURRENT) {
set_led(led, LED_GREEN);
} else {
set_led(led, LED_BLUE);
}
} else {
set_led(led, LED_RED);
}
k_usleep(500);
}
}